index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. var __read = (this && this.__read) || function (o, n) {
  2. var m = typeof Symbol === "function" && o[Symbol.iterator];
  3. if (!m) return o;
  4. var i = m.call(o), r, ar = [], e;
  5. try {
  6. while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
  7. }
  8. catch (error) { e = { error: error }; }
  9. finally {
  10. try {
  11. if (r && !r.done && (m = i["return"])) m.call(i);
  12. }
  13. finally { if (e) throw e.error; }
  14. }
  15. return ar;
  16. };
  17. var __spread = (this && this.__spread) || function () {
  18. for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
  19. return ar;
  20. };
  21. var DefaultNodeMenuKey = 'lf:defaultNodeMenu';
  22. var DefaultEdgeMenuKey = 'lf:defaultEdgeMenu';
  23. var DefaultGraphMenuKey = 'lf:defaultGraphMenu';
  24. var DefaultSelectionMenuKey = 'lf:defaultSelectionMenu';
  25. var Menu = /** @class */ (function () {
  26. function Menu(_a) {
  27. var _this = this;
  28. var lf = _a.lf;
  29. this.__menuDOM = document.createElement('ul');
  30. this.lf = lf;
  31. this.menuTypeMap = new Map();
  32. this.init();
  33. this.lf.setMenuConfig = function (config) {
  34. _this.setMenuConfig(config);
  35. };
  36. this.lf.addMenuConfig = function (config) {
  37. _this.addMenuConfig(config);
  38. };
  39. this.lf.setMenuByType = function (config) {
  40. _this.setMenuByType(config);
  41. };
  42. }
  43. /**
  44. * 初始化设置默认内置菜单栏
  45. */
  46. Menu.prototype.init = function () {
  47. var _this = this;
  48. var defaultNodeMenu = [
  49. {
  50. text: '删除',
  51. callback: function (node) {
  52. _this.lf.deleteNode(node.id);
  53. },
  54. },
  55. {
  56. text: '编辑文本',
  57. callback: function (node) {
  58. _this.lf.graphModel.editText(node.id);
  59. },
  60. },
  61. {
  62. text: '复制',
  63. callback: function (node) {
  64. _this.lf.cloneNode(node.id);
  65. },
  66. },
  67. ];
  68. this.menuTypeMap.set(DefaultNodeMenuKey, defaultNodeMenu);
  69. var defaultEdgeMenu = [
  70. {
  71. text: '删除',
  72. callback: function (edge) {
  73. _this.lf.deleteEdge(edge.id);
  74. },
  75. },
  76. {
  77. text: '编辑文本',
  78. callback: function (edge) {
  79. _this.lf.graphModel.editText(edge.id);
  80. },
  81. },
  82. ];
  83. this.menuTypeMap.set(DefaultEdgeMenuKey, defaultEdgeMenu);
  84. this.menuTypeMap.set(DefaultGraphMenuKey, []);
  85. var DefaultSelectionMenu = [
  86. {
  87. text: '删除',
  88. callback: function (elements) {
  89. _this.lf.clearSelectElements();
  90. elements.edges.forEach(function (edge) { return _this.lf.deleteEdge(edge.id); });
  91. elements.nodes.forEach(function (node) { return _this.lf.deleteNode(node.id); });
  92. },
  93. },
  94. ];
  95. this.menuTypeMap.set(DefaultSelectionMenuKey, DefaultSelectionMenu);
  96. };
  97. Menu.prototype.render = function (lf, container) {
  98. var _this = this;
  99. this.__container = container;
  100. this.__currentData = null; // 当前展示的菜单所属元素的model数据
  101. this.__menuDOM.className = 'lf-menu';
  102. container.appendChild(this.__menuDOM);
  103. // 将选项的click事件委托至menu容器
  104. // 在捕获阶段拦截并执行
  105. this.__menuDOM.addEventListener('click', function (event) {
  106. event.stopPropagation();
  107. var target = event.target;
  108. // 菜单有多层dom,需要精确获取菜单项所对应的dom
  109. // 除菜单项dom外,应考虑两种情况
  110. // 1. 菜单项的子元素 2. 菜单外层容器
  111. while (Array.from(target.classList).indexOf('lf-menu-item') === -1 && Array.from(target.classList).indexOf('lf-menu') === -1) {
  112. target = target.parentElement;
  113. }
  114. if (Array.from(target.classList).indexOf('lf-menu-item') > -1) {
  115. // 如果点击区域在菜单项内
  116. target.onclickCallback(_this.__currentData);
  117. // 点击后隐藏menu
  118. _this.__menuDOM.style.display = 'none';
  119. _this.__currentData = null;
  120. }
  121. else {
  122. // 如果点击区域不在菜单项内
  123. console.warn('点击区域不在菜单项内,请检查代码!');
  124. }
  125. }, true);
  126. // 通过事件控制菜单的显示和隐藏
  127. this.lf.on('node:contextmenu', function (_a) {
  128. var data = _a.data, position = _a.position;
  129. var _b = position.domOverlayPosition, x = _b.x, y = _b.y;
  130. var id = data.id;
  131. var model = _this.lf.graphModel.getNodeModelById(id);
  132. var menuList = [];
  133. var typeMenus = _this.menuTypeMap.get(model.type);
  134. // 如果单个节点自定义了节点,以单个节点自定义为准
  135. if (model && model.menu && Array.isArray(model.menu)) {
  136. menuList = model.menu;
  137. }
  138. else if (typeMenus) { // 如果定义当前节点类型的元素
  139. menuList = typeMenus;
  140. }
  141. else { // 最后取全局默认
  142. menuList = _this.menuTypeMap.get(DefaultNodeMenuKey);
  143. }
  144. _this.__currentData = data;
  145. _this.showMenu(x, y, menuList);
  146. });
  147. this.lf.on('edge:contextmenu', function (_a) {
  148. var data = _a.data, position = _a.position;
  149. var _b = position.domOverlayPosition, x = _b.x, y = _b.y;
  150. var id = data.id;
  151. var model = _this.lf.graphModel.getEdgeModelById(id);
  152. var menuList = [];
  153. var typeMenus = _this.menuTypeMap.get(model.type);
  154. // 如果单个节点自定义了边
  155. if (model && model.menu && Array.isArray(model.menu)) {
  156. menuList = model.menu;
  157. }
  158. else if (typeMenus) { // 如果定义当前边类型的元素
  159. menuList = typeMenus;
  160. }
  161. else { // 最后取全局默认
  162. menuList = _this.menuTypeMap.get(DefaultEdgeMenuKey);
  163. }
  164. _this.__currentData = data;
  165. _this.showMenu(x, y, menuList);
  166. });
  167. this.lf.on('blank:contextmenu', function (_a) {
  168. var position = _a.position;
  169. var menuList = _this.menuTypeMap.get(DefaultGraphMenuKey);
  170. var _b = position.domOverlayPosition, x = _b.x, y = _b.y;
  171. _this.showMenu(x, y, menuList);
  172. });
  173. this.lf.on('selection:contextmenu', function (_a) {
  174. var data = _a.data, position = _a.position;
  175. var menuList = _this.menuTypeMap.get(DefaultSelectionMenuKey);
  176. var _b = position.domOverlayPosition, x = _b.x, y = _b.y;
  177. _this.__currentData = data;
  178. _this.showMenu(x, y, menuList);
  179. });
  180. this.lf.on('node:mousedown', function () {
  181. _this.__menuDOM.style.display = 'none';
  182. });
  183. this.lf.on('edge:click', function () {
  184. _this.__menuDOM.style.display = 'none';
  185. });
  186. this.lf.on('blank:click', function () {
  187. _this.__menuDOM.style.display = 'none';
  188. });
  189. };
  190. Menu.prototype.destroy = function () {
  191. var _a;
  192. (_a = this === null || this === void 0 ? void 0 : this.__container) === null || _a === void 0 ? void 0 : _a.removeChild(this.__menuDOM);
  193. this.__menuDOM = null;
  194. };
  195. Menu.prototype.showMenu = function (x, y, menuList) {
  196. if (!menuList || !menuList.length)
  197. return;
  198. var menu = this.__menuDOM;
  199. // 菜单容器不变,需要先清空内部的菜单项
  200. menu.innerHTML = '';
  201. menu.append.apply(menu, __spread(this.__getMenuDom(menuList)));
  202. // 菜单中没有项,不显示
  203. if (!menu.children.length)
  204. return;
  205. menu.style.display = 'block';
  206. menu.style.top = y + "px";
  207. menu.style.left = x + "px";
  208. };
  209. /**
  210. * 设置指定类型元素的菜单
  211. */
  212. Menu.prototype.setMenuByType = function (config) {
  213. if (!config.type || !config.menu) {
  214. return;
  215. }
  216. this.menuTypeMap.set(config.type, config.menu);
  217. };
  218. /**
  219. * 获取 Menu DOM
  220. * @param list 菜单项
  221. * @return 菜单项 DOM
  222. */
  223. Menu.prototype.__getMenuDom = function (list) {
  224. var menuList = [];
  225. list && list.length > 0 && list.forEach(function (item) {
  226. var element = document.createElement('li');
  227. if (item.className) {
  228. element.className = "lf-menu-item " + item.className;
  229. }
  230. else {
  231. element.className = 'lf-menu-item';
  232. }
  233. if (item.icon === true) {
  234. var icon = document.createElement('span');
  235. icon.className = 'lf-menu-item-icon';
  236. element.appendChild(icon);
  237. }
  238. var text = document.createElement('span');
  239. text.className = 'lf-menu-item-text';
  240. if (item.text) {
  241. text.innerText = item.text;
  242. }
  243. element.appendChild(text);
  244. element.onclickCallback = item.callback;
  245. menuList.push(element);
  246. });
  247. return menuList;
  248. };
  249. // 复写菜单
  250. Menu.prototype.setMenuConfig = function (config) {
  251. if (!config) {
  252. return;
  253. }
  254. // node
  255. config.nodeMenu !== undefined
  256. && this.menuTypeMap.set(DefaultNodeMenuKey, config.nodeMenu ? config.nodeMenu : []);
  257. // edge
  258. config.edgeMenu !== undefined
  259. && this.menuTypeMap.set(DefaultEdgeMenuKey, config.edgeMenu ? config.edgeMenu : []);
  260. // graph
  261. config.graphMenu !== undefined
  262. && this.menuTypeMap.set(DefaultGraphMenuKey, config.graphMenu ? config.graphMenu : []);
  263. };
  264. // 在默认菜单后面追加菜单项
  265. Menu.prototype.addMenuConfig = function (config) {
  266. if (!config) {
  267. return;
  268. }
  269. // 追加项时,只支持数组类型,对false不做操作
  270. if (Array.isArray(config.nodeMenu)) {
  271. var menuList = this.menuTypeMap.get(DefaultNodeMenuKey);
  272. this.menuTypeMap.set(DefaultNodeMenuKey, menuList.concat(config.nodeMenu));
  273. }
  274. if (Array.isArray(config.edgeMenu)) {
  275. var menuList = this.menuTypeMap.get(DefaultEdgeMenuKey);
  276. this.menuTypeMap.set(DefaultEdgeMenuKey, menuList.concat(config.edgeMenu));
  277. }
  278. if (Array.isArray(config.graphMenu)) {
  279. var menuList = this.menuTypeMap.get(DefaultGraphMenuKey);
  280. this.menuTypeMap.set(DefaultGraphMenuKey, menuList.concat(config.graphMenu));
  281. }
  282. };
  283. /**
  284. * @deprecated
  285. * 复写添加
  286. */
  287. Menu.prototype.changeMenuItem = function (type, config) {
  288. if (type === 'add')
  289. this.addMenuConfig(config);
  290. else if (type === 'reset')
  291. this.setMenuConfig(config);
  292. else {
  293. throw new Error('The first parameter of changeMenuConfig should be \'add\' or \'reset\'');
  294. }
  295. };
  296. Menu.pluginName = 'menu';
  297. return Menu;
  298. }());
  299. export default Menu;
  300. export { Menu, };