index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. var __values = (this && this.__values) || function(o) {
  2. var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
  3. if (m) return m.call(o);
  4. if (o && typeof o.length === "number") return {
  5. next: function () {
  6. if (o && i >= o.length) o = void 0;
  7. return { value: o && o[i++], done: !o };
  8. }
  9. };
  10. throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
  11. };
  12. import { throttle } from 'lodash-es';
  13. var MiniMap = /** @class */ (function () {
  14. function MiniMap(_a) {
  15. var _this = this;
  16. var lf = _a.lf, LogicFlow = _a.LogicFlow, options = _a.options;
  17. this.lf = null;
  18. this.container = null;
  19. this.miniMapWrap = null;
  20. this.miniMapContainer = null;
  21. this.lfMap = null;
  22. this.viewport = null;
  23. this.width = 150;
  24. this.height = 220;
  25. this.leftPosition = undefined;
  26. this.topPosition = undefined;
  27. this.rightPosition = undefined;
  28. this.bottomPosition = undefined;
  29. this.miniMapWidth = 450;
  30. this.miniMapHeight = 660;
  31. this.viewPortTop = 0;
  32. this.viewPortLeft = 0;
  33. this.startPosition = null;
  34. this.viewPortScale = 1;
  35. this.viewPortWidth = 150;
  36. this.viewPortHeight = 75;
  37. this.resetDataX = 0;
  38. this.resetDataY = 0;
  39. this.LogicFlow = null;
  40. this.isShow = false;
  41. this.isShowHeader = true;
  42. this.isShowCloseIcon = true;
  43. this.dragging = false;
  44. this.disabledPlugins = ['miniMap', 'control', 'selectionSelect'];
  45. /**
  46. * 显示mini map
  47. */
  48. this.show = function (leftPosition, topPosition) {
  49. _this.setView();
  50. if (!_this.isShow) {
  51. _this.createMiniMap(leftPosition, topPosition);
  52. }
  53. _this.isShow = true;
  54. };
  55. /**
  56. * 隐藏mini map
  57. */
  58. this.hide = function () {
  59. if (_this.isShow) {
  60. _this.removeMiniMap();
  61. }
  62. _this.isShow = false;
  63. };
  64. this.reset = function () {
  65. _this.lf.resetTranslate();
  66. _this.lf.resetZoom();
  67. _this.hide();
  68. _this.show();
  69. };
  70. this.startDrag = function (e) {
  71. document.addEventListener('mousemove', _this.drag);
  72. document.addEventListener('mouseup', _this.drop);
  73. _this.startPosition = {
  74. x: e.x,
  75. y: e.y,
  76. };
  77. };
  78. this.moveViewport = function (top, left) {
  79. var viewStyle = _this.viewport.style;
  80. _this.viewPortTop = top;
  81. _this.viewPortLeft = left;
  82. viewStyle.top = _this.viewPortTop + "px";
  83. viewStyle.left = _this.viewPortLeft + "px";
  84. };
  85. this.drag = function (e) {
  86. _this.dragging = true;
  87. var top = _this.viewPortTop + e.y - _this.startPosition.y;
  88. var left = _this.viewPortLeft + e.x - _this.startPosition.x;
  89. _this.moveViewport(top, left);
  90. _this.startPosition = {
  91. x: e.x,
  92. y: e.y,
  93. };
  94. var centerX = (_this.viewPortLeft + _this.viewPortWidth / 2)
  95. / _this.viewPortScale;
  96. var centerY = (_this.viewPortTop + _this.viewPortHeight / 2)
  97. / _this.viewPortScale;
  98. _this.lf.focusOn({
  99. coordinate: {
  100. x: centerX + _this.resetDataX,
  101. y: centerY + _this.resetDataY,
  102. },
  103. });
  104. };
  105. this.drop = function () {
  106. document.removeEventListener('mousemove', _this.drag);
  107. document.removeEventListener('mouseup', _this.drop);
  108. var top = _this.viewPortTop;
  109. var left = _this.viewPortLeft;
  110. if (_this.viewPortLeft > _this.width) {
  111. left = _this.width - _this.viewPortWidth;
  112. }
  113. if (_this.viewPortTop > _this.height) {
  114. top = _this.height - _this.viewPortHeight;
  115. }
  116. if (_this.viewPortLeft < -_this.width) {
  117. left = 0;
  118. }
  119. if (_this.viewPortTop < -_this.height) {
  120. top = 0;
  121. }
  122. _this.moveViewport(top, left);
  123. };
  124. this.mapClick = function (e) {
  125. if (_this.dragging) {
  126. _this.dragging = false;
  127. }
  128. else {
  129. var layerX = e.layerX, layerY = e.layerY;
  130. var ViewPortCenterX = layerX;
  131. var ViewPortCenterY = layerY;
  132. var graphData = _this.lf.getGraphRawData();
  133. var _a = _this.getBounds(graphData), left = _a.left, top_1 = _a.top;
  134. var resetGraphX = left + ViewPortCenterX / _this.viewPortScale;
  135. var resetGraphY = top_1 + ViewPortCenterY / _this.viewPortScale;
  136. _this.lf.focusOn({ coordinate: { x: resetGraphX, y: resetGraphY } });
  137. }
  138. };
  139. this.lf = lf;
  140. if (options && options.MiniMap) {
  141. this.setOption(options);
  142. }
  143. this.miniMapWidth = lf.graphModel.width;
  144. this.miniMapHeight = (lf.graphModel.width * this.height) / this.width;
  145. this.LogicFlow = LogicFlow;
  146. this.initMiniMap();
  147. }
  148. MiniMap.prototype.render = function (lf, container) {
  149. var _this = this;
  150. this.container = container;
  151. this.lf.on('history:change', function () {
  152. if (_this.isShow) {
  153. _this.setView();
  154. }
  155. });
  156. this.lf.on('graph:transform', throttle(function () {
  157. // 小地图已展示,并且没有拖拽小地图视口
  158. if (_this.isShow && !_this.dragging) {
  159. _this.setView();
  160. }
  161. }, 300));
  162. };
  163. MiniMap.prototype.init = function (option) {
  164. this.disabledPlugins = this.disabledPlugins.concat(option.disabledPlugins || []);
  165. };
  166. MiniMap.prototype.setOption = function (options) {
  167. var _a = options.MiniMap, _b = _a.width, width = _b === void 0 ? 150 : _b, _c = _a.height, height = _c === void 0 ? 220 : _c, _d = _a.isShowHeader, isShowHeader = _d === void 0 ? true : _d, _e = _a.isShowCloseIcon, isShowCloseIcon = _e === void 0 ? true : _e, _f = _a.leftPosition, leftPosition = _f === void 0 ? 0 : _f, _g = _a.topPosition, topPosition = _g === void 0 ? 0 : _g, rightPosition = _a.rightPosition, bottomPosition = _a.bottomPosition;
  168. this.width = width;
  169. this.height = height;
  170. this.isShowHeader = isShowHeader;
  171. this.isShowCloseIcon = isShowCloseIcon;
  172. this.viewPortWidth = width;
  173. this.leftPosition = leftPosition;
  174. this.topPosition = topPosition;
  175. this.rightPosition = rightPosition;
  176. this.bottomPosition = bottomPosition;
  177. };
  178. MiniMap.prototype.initMiniMap = function () {
  179. var miniMapWrap = document.createElement('div');
  180. miniMapWrap.className = 'lf-mini-map-graph';
  181. miniMapWrap.style.width = this.width + 4 + "px";
  182. miniMapWrap.style.height = this.height + "px";
  183. this.lfMap = new this.LogicFlow({
  184. width: this.lf.graphModel.width,
  185. height: (this.lf.graphModel.width * this.height) / this.width,
  186. container: miniMapWrap,
  187. isSilentMode: true,
  188. stopZoomGraph: true,
  189. stopScrollGraph: true,
  190. stopMoveGraph: true,
  191. hideAnchors: true,
  192. hoverOutline: false,
  193. disabledPlugins: this.disabledPlugins,
  194. });
  195. // minimap中禁用adapter。
  196. this.lfMap.adapterIn = function (a) { return a; };
  197. this.lfMap.adapterOut = function (a) { return a; };
  198. this.miniMapWrap = miniMapWrap;
  199. this.createViewPort();
  200. miniMapWrap.addEventListener('click', this.mapClick);
  201. };
  202. MiniMap.prototype.createMiniMap = function (left, top) {
  203. var miniMapContainer = document.createElement('div');
  204. miniMapContainer.appendChild(this.miniMapWrap);
  205. if (typeof left !== 'undefined' || typeof top !== 'undefined') {
  206. miniMapContainer.style.left = (left || 0) + "px";
  207. miniMapContainer.style.top = (top || 0) + "px";
  208. }
  209. else {
  210. if (typeof this.rightPosition !== 'undefined') {
  211. miniMapContainer.style.right = this.rightPosition + "px";
  212. }
  213. else if (typeof this.leftPosition !== 'undefined') {
  214. miniMapContainer.style.left = this.leftPosition + "px";
  215. }
  216. if (typeof this.bottomPosition !== 'undefined') {
  217. miniMapContainer.style.bottom = this.bottomPosition + "px";
  218. }
  219. else if (typeof this.topPosition !== 'undefined') {
  220. miniMapContainer.style.top = this.topPosition + "px";
  221. }
  222. }
  223. miniMapContainer.style.position = 'absolute';
  224. miniMapContainer.className = 'lf-mini-map';
  225. if (!this.isShowCloseIcon) {
  226. miniMapContainer.classList.add('lf-mini-map-no-close-icon');
  227. }
  228. if (!this.isShowHeader) {
  229. miniMapContainer.classList.add('lf-mini-map-no-header');
  230. }
  231. this.container.appendChild(miniMapContainer);
  232. this.miniMapWrap.appendChild(this.viewport);
  233. var header = document.createElement('div');
  234. header.className = 'lf-mini-map-header';
  235. header.innerText = MiniMap.headerTitle;
  236. miniMapContainer.appendChild(header);
  237. var close = document.createElement('span');
  238. close.className = 'lf-mini-map-close';
  239. close.addEventListener('click', this.hide);
  240. miniMapContainer.appendChild(close);
  241. this.miniMapContainer = miniMapContainer;
  242. };
  243. MiniMap.prototype.removeMiniMap = function () {
  244. this.container.removeChild(this.miniMapContainer);
  245. };
  246. /**
  247. * 计算所有图形一起,占领的区域范围。
  248. * @param data
  249. */
  250. MiniMap.prototype.getBounds = function (data) {
  251. var left = 0;
  252. var right = this.miniMapWidth;
  253. var top = 0;
  254. var bottom = this.miniMapHeight;
  255. var nodes = data.nodes;
  256. if (nodes && nodes.length > 0) {
  257. // 因为获取的节点不知道真实的宽高,这里需要补充一点数值
  258. nodes.forEach(function (_a) {
  259. var x = _a.x, y = _a.y, _b = _a.width, width = _b === void 0 ? 200 : _b, _c = _a.height, height = _c === void 0 ? 200 : _c;
  260. var nodeLeft = x - width / 2;
  261. var nodeRight = x + width / 2;
  262. var nodeTop = y - height / 2;
  263. var nodeBottom = y + height / 2;
  264. left = nodeLeft < left ? nodeLeft : left;
  265. right = nodeRight > right ? nodeRight : right;
  266. top = nodeTop < top ? nodeTop : top;
  267. bottom = nodeBottom > bottom ? nodeBottom : bottom;
  268. });
  269. }
  270. return {
  271. left: left,
  272. top: top,
  273. bottom: bottom,
  274. right: right,
  275. };
  276. };
  277. /**
  278. * 将负值的平移转换为正值。
  279. * 保证渲染的时候,minimap能完全展示。
  280. * 获取将画布所有元素平移到0,0开始时,所有节点数据
  281. */
  282. MiniMap.prototype.resetData = function (data) {
  283. var nodes = data.nodes, edges = data.edges;
  284. var left = 0;
  285. var top = 0;
  286. if (nodes && nodes.length > 0) {
  287. // 因为获取的节点不知道真实的宽高,这里需要补充一点数值
  288. nodes.forEach(function (_a) {
  289. var x = _a.x, y = _a.y, _b = _a.width, width = _b === void 0 ? 200 : _b, _c = _a.height, height = _c === void 0 ? 200 : _c;
  290. var nodeLeft = x - width / 2;
  291. var nodeTop = y - height / 2;
  292. left = nodeLeft < left ? nodeLeft : left;
  293. top = nodeTop < top ? nodeTop : top;
  294. });
  295. if (left < 0 || top < 0) {
  296. this.resetDataX = left;
  297. this.resetDataY = top;
  298. nodes.forEach(function (node) {
  299. node.x = node.x - left;
  300. node.y = node.y - top;
  301. if (node.text) {
  302. node.text.x = node.text.x - left;
  303. node.text.y = node.text.y - top;
  304. }
  305. });
  306. edges.forEach(function (edge) {
  307. if (edge.startPoint) {
  308. edge.startPoint.x = edge.startPoint.x - left;
  309. edge.startPoint.y = edge.startPoint.y - top;
  310. }
  311. if (edge.endPoint) {
  312. edge.endPoint.x = edge.endPoint.x - left;
  313. edge.endPoint.y = edge.endPoint.y - top;
  314. }
  315. if (edge.text) {
  316. edge.text.x = edge.text.x - left;
  317. edge.text.y = edge.text.y - top;
  318. }
  319. if (edge.pointsList) {
  320. edge.pointsList.forEach(function (point) {
  321. point.x = point.x - left;
  322. point.y = point.y - top;
  323. });
  324. }
  325. });
  326. }
  327. }
  328. return data;
  329. };
  330. /**
  331. * 显示导航
  332. * 显示视口范围
  333. * 1. 基于画布的范围比例,设置视口范围比例。宽度默认为导航宽度。
  334. */
  335. MiniMap.prototype.setView = function () {
  336. var e_1, _a;
  337. // 1. 获取到图中所有的节点中的位置,将其偏移到原点开始(避免节点位置为负的时候无法展示问题)。
  338. var graphData = this.lf.getGraphRawData();
  339. var data = this.resetData(graphData);
  340. // 由于随时都会有新节点注册进来,需要同步将注册的
  341. var viewMap = this.lf.viewMap;
  342. var modelMap = this.lf.graphModel.modelMap;
  343. var minimapViewMap = this.lfMap.viewMap;
  344. try {
  345. // todo: no-restricted-syntax
  346. for (var _b = __values(viewMap.keys()), _c = _b.next(); !_c.done; _c = _b.next()) {
  347. var key = _c.value;
  348. if (!minimapViewMap.has(key)) {
  349. this.lfMap.setView(key, viewMap.get(key));
  350. this.lfMap.graphModel.modelMap.set(key, modelMap.get(key));
  351. }
  352. }
  353. }
  354. catch (e_1_1) { e_1 = { error: e_1_1 }; }
  355. finally {
  356. try {
  357. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  358. }
  359. finally { if (e_1) throw e_1.error; }
  360. }
  361. this.lfMap.render(data);
  362. // 2. 将偏移后的数据渲染到minimap画布上
  363. // 3. 计算出所有节点在一起的边界。
  364. var _d = this.getBounds(data), left = _d.left, top = _d.top, right = _d.right, bottom = _d.bottom;
  365. // 4. 计算所有节点的边界与minimap看板的边界的比例.
  366. var realWidthScale = this.width / (right - left);
  367. var realHeightScale = this.height / (bottom - top);
  368. // 5. 取比例最小的值,将渲染的画布缩小对应比例。
  369. var innerStyle = this.miniMapWrap.firstChild.style;
  370. var scale = Math.min(realWidthScale, realHeightScale);
  371. innerStyle.transform = "matrix(" + scale + ", 0, 0, " + scale + ", 0, 0)";
  372. innerStyle.transformOrigin = 'left top';
  373. innerStyle.height = bottom - Math.min(top, 0) + "px";
  374. innerStyle.width = right - Math.min(left, 0) + "px";
  375. this.viewPortScale = scale;
  376. this.setViewPort(scale, {
  377. left: left,
  378. top: top,
  379. right: right,
  380. bottom: bottom,
  381. });
  382. };
  383. // 设置视口
  384. MiniMap.prototype.setViewPort = function (scale, _a) {
  385. var left = _a.left, right = _a.right, top = _a.top, bottom = _a.bottom;
  386. var viewStyle = this.viewport.style;
  387. viewStyle.width = this.viewPortWidth + "px";
  388. viewStyle.height = (this.viewPortWidth) / (this.lf.graphModel.width / this.lf.graphModel.height) + "px";
  389. var _b = this.lf.getTransform(), TRANSLATE_X = _b.TRANSLATE_X, TRANSLATE_Y = _b.TRANSLATE_Y, SCALE_X = _b.SCALE_X, SCALE_Y = _b.SCALE_Y;
  390. var realWidth = right - left;
  391. // 视口宽 = 小地图宽 / (所有元素一起占据的真实宽 / 绘布宽)
  392. var viewPortWidth = (this.width) / (realWidth / this.lf.graphModel.width);
  393. // 实际视口宽 = 小地图宽 * 占宽度比例
  394. var realViewPortWidth = this.width * (viewPortWidth / this.width);
  395. var graphRatio = (this.lf.graphModel.width / this.lf.graphModel.height);
  396. // 视口实际高 = 视口实际宽 / (绘布宽 / 绘布高)
  397. var realViewPortHeight = realViewPortWidth / graphRatio;
  398. var graphData = this.lf.getGraphRawData();
  399. var _c = this.getBounds(graphData), graphLeft = _c.left, graphTop = _c.top;
  400. var viewportLeft = graphLeft;
  401. var viewportTop = graphTop;
  402. viewportLeft += TRANSLATE_X / SCALE_X;
  403. viewportTop += TRANSLATE_Y / SCALE_Y;
  404. this.viewPortTop = viewportTop > 0 ? 0 : (-viewportTop * scale);
  405. this.viewPortLeft = viewportLeft > 0 ? 0 : (-viewportLeft * scale);
  406. this.viewPortWidth = realViewPortWidth;
  407. this.viewPortHeight = realViewPortHeight;
  408. viewStyle.top = this.viewPortTop + "px";
  409. viewStyle.left = this.viewPortLeft + "px";
  410. viewStyle.width = realViewPortWidth / SCALE_X + "px";
  411. viewStyle.height = realViewPortHeight / SCALE_Y + "px";
  412. };
  413. // 预览视窗
  414. MiniMap.prototype.createViewPort = function () {
  415. var div = document.createElement('div');
  416. div.className = 'lf-minimap-viewport';
  417. div.addEventListener('mousedown', this.startDrag);
  418. this.viewport = div;
  419. };
  420. MiniMap.pluginName = 'miniMap';
  421. MiniMap.width = 150;
  422. MiniMap.height = 220;
  423. MiniMap.viewPortWidth = 150;
  424. MiniMap.viewPortHeight = 75;
  425. MiniMap.isShowHeader = true;
  426. MiniMap.isShowCloseIcon = true;
  427. MiniMap.leftPosition = 0;
  428. MiniMap.topPosition = 0;
  429. MiniMap.rightPosition = null;
  430. MiniMap.bottomPosition = null;
  431. MiniMap.headerTitle = '导航';
  432. return MiniMap;
  433. }());
  434. export default MiniMap;
  435. export { MiniMap };