index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. "use strict";
  2. /**
  3. * 自动布局插件
  4. * 依赖flowPath插件
  5. * 未完善
  6. */
  7. var __assign = (this && this.__assign) || function () {
  8. __assign = Object.assign || function(t) {
  9. for (var s, i = 1, n = arguments.length; i < n; i++) {
  10. s = arguments[i];
  11. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  12. t[p] = s[p];
  13. }
  14. return t;
  15. };
  16. return __assign.apply(this, arguments);
  17. };
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. exports.AutoLayout = void 0;
  20. var POSITION_TYPE = {
  21. LEFT_TOP: -1,
  22. LEFT: 0,
  23. LEFT_BOTTOM: 1,
  24. };
  25. var AutoLayout = /** @class */ (function () {
  26. function AutoLayout(_a) {
  27. var _this = this;
  28. var lf = _a.lf;
  29. this.lf = lf;
  30. /**
  31. * 用于记录上一次调用layout时计算出的trunk
  32. * 当旧trunk和新trunk长度一致时,用于选择旧trunk,
  33. * a->b->c->d
  34. * |->e
  35. * e后面新增f节点时候,旧逻辑会返回新trunk[a,b,e,f]
  36. * 界面布局变成
  37. * a->b->e->f
  38. * |->c->d
  39. * 其实只想要这样 尽量少变化
  40. * a->b->c->d
  41. * |->e->f
  42. * */
  43. this.trunk = [];
  44. // 给lf添加方法
  45. lf.layout = function (startNodeType) {
  46. var data = _this.lf.getGraphRawData();
  47. _this.lf.setStartNodeType(startNodeType);
  48. var path = _this.lf.getPathes();
  49. _this.levelHeight = [];
  50. _this.newNodeMap = new Map();
  51. return _this.layout(data, path);
  52. };
  53. }
  54. // 1) 将所有节点和边的坐标删除。节点上的文本改成偏移量。
  55. // 2) 找到长度最长的路径,作为基准路径。
  56. // 3) 依次计算
  57. // 拿到最长的路径。
  58. // nodes: [], edges: [],
  59. AutoLayout.prototype.layout = function (data, path) {
  60. var _this = this;
  61. var trunk = [];
  62. path.forEach(function (p) {
  63. var elements = p.elements;
  64. if (elements.length > trunk.length) {
  65. trunk = elements;
  66. }
  67. else if (elements.length === trunk.length) {
  68. // 考虑是否替换为旧的trunk
  69. if (JSON.stringify(elements) === JSON.stringify(_this.trunk)) {
  70. trunk = _this.trunk;
  71. }
  72. }
  73. });
  74. // 记录上一次trunk
  75. this.trunk = trunk;
  76. var nodeMap = this.formatData(data);
  77. var newGraphData = {
  78. nodes: [],
  79. edges: [],
  80. };
  81. // 从后向前布局
  82. for (var i = trunk.length - 1; i >= 0; i--) {
  83. this.setNodePosition(trunk[i], nodeMap, newGraphData, i, 1);
  84. }
  85. this.lf.graphModel.graphDataToModel(newGraphData);
  86. };
  87. // 1) 需要知道下一层级已占高度。
  88. // 2) 基于自己的高度,判断下一个层级的高度
  89. AutoLayout.prototype.setNodePosition = function (nodeId, nodeMap, newGraphData, xLevel, yLevel) {
  90. var _this = this;
  91. var n = nodeMap[nodeId];
  92. var text = n.text, type = n.type, next = n.next, properties = n.properties;
  93. var x = xLevel * 160 + 40;
  94. var y = yLevel * 120;
  95. var nodeData = {
  96. id: nodeId,
  97. x: x,
  98. text: text,
  99. y: y,
  100. type: type,
  101. properties: properties,
  102. };
  103. if (text && typeof text === 'object') {
  104. nodeData.text = __assign(__assign({}, text), { x: x + text.x, y: y + text.y });
  105. }
  106. this.newNodeMap.set(nodeData.id, {
  107. x: nodeData.x,
  108. y: nodeData.y,
  109. type: type,
  110. });
  111. newGraphData.nodes.push(nodeData);
  112. n.isFixed = true;
  113. this.addLevelHeight(xLevel, 1);
  114. if (next && next.length > 0) {
  115. next.forEach(function (nextInfo) {
  116. // 如果下一个节点还没有被定位,那么设置其定位
  117. var n1 = nodeMap[nextInfo.nodeId];
  118. if (!n1.isFixed) {
  119. var nextYLevel = _this.getLevelHeight(xLevel + 1);
  120. _this.addLevelHeight(xLevel, 1);
  121. _this.setNodePosition(nextInfo.nodeId, nodeMap, newGraphData, xLevel + 1, nextYLevel + 1);
  122. }
  123. else {
  124. // todo: 如果下一个节点是已经定位的,则需要考虑边的规避
  125. }
  126. // 设置连接到下一个节点的边
  127. // 1) 起始位置为source节点的下方,结束位置为target节点左边。
  128. // 2) 计算折线
  129. newGraphData.edges.push(__assign({ id: nextInfo.edgeId, type: nextInfo.edgeType, sourceNodeId: nodeId, targetNodeId: nextInfo.nodeId, properties: nextInfo.properties, text: nextInfo.text }, _this.getEdgeDataPoints(nodeId, nextInfo.nodeId)));
  130. });
  131. }
  132. return nodeData;
  133. };
  134. /**
  135. * 1. 处理边上的文本
  136. * 2. 主干节点之间直接的边
  137. * 3. 一个节点被多个连接作为目标节点,合理分配锚点位置。
  138. */
  139. AutoLayout.prototype.getEdgeDataPoints = function (sourceNodeId, targetNodeId) {
  140. var source = this.newNodeMap.get(sourceNodeId);
  141. var target = this.newNodeMap.get(targetNodeId);
  142. var _a = this.getShape(sourceNodeId), width = _a.width, height = _a.height;
  143. var _b = this.getShape(targetNodeId), targetWidth = _b.width, targetHeight = _b.height;
  144. var positionType = this.getRelativePosition(source, target);
  145. var startPoint = {
  146. x: source.x,
  147. y: source.y,
  148. };
  149. var endPoint = {
  150. x: target.x,
  151. y: target.y,
  152. };
  153. switch (positionType) {
  154. case POSITION_TYPE.LEFT:
  155. startPoint.x = source.x + width / 2;
  156. endPoint.x = target.x - targetWidth / 2;
  157. break;
  158. case POSITION_TYPE.LEFT_TOP:
  159. startPoint.y = source.y + height / 2;
  160. endPoint.x = target.x - targetWidth / 2;
  161. break;
  162. case POSITION_TYPE.LEFT_BOTTOM:
  163. startPoint.x = source.x + width / 2;
  164. endPoint.y = target.y + targetHeight / 2;
  165. break;
  166. default:
  167. break;
  168. }
  169. return {
  170. startPoint: startPoint,
  171. endPoint: endPoint,
  172. };
  173. };
  174. /**
  175. * 获取边的连接节点相对位置。
  176. * source一定在target左边。
  177. * 1. 如果source和target在同一x, y坐标内容。
  178. * 2. 如果source在target左上方。
  179. * 3. 如果source在target左下方。
  180. */
  181. AutoLayout.prototype.getRelativePosition = function (source, target) {
  182. var y = source.y;
  183. var y1 = target.y;
  184. var positionType;
  185. if (y < y1) {
  186. positionType = -1;
  187. }
  188. else if (y === y1) {
  189. positionType = 0;
  190. }
  191. else {
  192. positionType = 1;
  193. }
  194. return positionType;
  195. };
  196. /**
  197. * 获取边节点图形的宽高。
  198. */
  199. AutoLayout.prototype.getShape = function (nodeId) {
  200. var nodeModel = this.lf.getNodeModelById(nodeId);
  201. return {
  202. height: nodeModel.height,
  203. width: nodeModel.width,
  204. };
  205. };
  206. AutoLayout.prototype.formatData = function (data) {
  207. var nodeMap = data.nodes.reduce(function (nMap, node) {
  208. var type = node.type, properties = node.properties, text = node.text, x = node.x, y = node.y;
  209. if (text && typeof text === 'object') {
  210. // 坐标转换为偏移量
  211. text.x = text.x - x;
  212. text.y = text.y - y;
  213. }
  214. nMap[node.id] = {
  215. type: type,
  216. properties: properties,
  217. text: text,
  218. prev: [],
  219. next: [],
  220. };
  221. return nMap;
  222. }, {});
  223. data.edges.forEach(function (edge) {
  224. var sourceNodeId = edge.sourceNodeId, targetNodeId = edge.targetNodeId, id = edge.id, properties = edge.properties, text = edge.text;
  225. var newText = text;
  226. if (typeof text === 'object') {
  227. newText = text.value;
  228. }
  229. nodeMap[sourceNodeId].next.push({
  230. edgeId: id,
  231. nodeId: targetNodeId,
  232. edgeType: edge.type,
  233. properties: properties,
  234. text: newText,
  235. });
  236. nodeMap[targetNodeId].prev.push({
  237. edgeId: id,
  238. nodeId: sourceNodeId,
  239. properties: properties,
  240. text: newText,
  241. });
  242. });
  243. return nodeMap;
  244. };
  245. AutoLayout.prototype.addLevelHeight = function (level, height, isNegative) {
  246. if (height === void 0) { height = 1; }
  247. if (isNegative === void 0) { isNegative = false; }
  248. var l = this.levelHeight[level];
  249. if (!l) {
  250. l = {
  251. positiveHeight: 0,
  252. negativeHeight: 0,
  253. };
  254. this.levelHeight[level] = l;
  255. }
  256. isNegative ? (l.negativeHeight -= height) : (l.positiveHeight += height);
  257. };
  258. AutoLayout.prototype.getLevelHeight = function (level, isNegative) {
  259. if (isNegative === void 0) { isNegative = false; }
  260. var val = this.levelHeight[level];
  261. if (!val) {
  262. return 0;
  263. }
  264. return isNegative ? val.negativeHeight : val.positiveHeight;
  265. };
  266. AutoLayout.pluginName = 'AutoLayout';
  267. return AutoLayout;
  268. }());
  269. exports.AutoLayout = AutoLayout;