view.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. "use strict";
  2. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  3. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  4. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  5. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  6. return c > 3 && r && Object.defineProperty(target, key, r), r;
  7. };
  8. Object.defineProperty(exports, "__esModule", { value: true });
  9. exports.GraphView = void 0;
  10. const x6_common_1 = require("@antv/x6-common");
  11. const model_1 = require("../model");
  12. const config_1 = require("../config");
  13. const view_1 = require("../view");
  14. class GraphView extends view_1.View {
  15. /** Graph's `this.container` is from outer, should not dispose */
  16. get disposeContainer() {
  17. return false;
  18. }
  19. get options() {
  20. return this.graph.options;
  21. }
  22. constructor(graph) {
  23. super();
  24. this.graph = graph;
  25. const { selectors, fragment } = view_1.Markup.parseJSONMarkup(GraphView.markup);
  26. this.background = selectors.background;
  27. this.grid = selectors.grid;
  28. this.svg = selectors.svg;
  29. this.defs = selectors.defs;
  30. this.viewport = selectors.viewport;
  31. this.primer = selectors.primer;
  32. this.stage = selectors.stage;
  33. this.decorator = selectors.decorator;
  34. this.overlay = selectors.overlay;
  35. this.container = this.options.container;
  36. this.restore = GraphView.snapshoot(this.container);
  37. x6_common_1.Dom.addClass(this.container, this.prefixClassName('graph'));
  38. x6_common_1.Dom.append(this.container, fragment);
  39. this.delegateEvents();
  40. }
  41. delegateEvents() {
  42. const ctor = this.constructor;
  43. super.delegateEvents(ctor.events);
  44. return this;
  45. }
  46. /**
  47. * Guard the specified event. If the event is not interesting, it
  48. * returns `true`, otherwise returns `false`.
  49. */
  50. guard(e, view) {
  51. // handled as `contextmenu` type
  52. if (e.type === 'mousedown' && e.button === 2) {
  53. return true;
  54. }
  55. if (this.options.guard && this.options.guard(e, view)) {
  56. return true;
  57. }
  58. if (e.data && e.data.guarded !== undefined) {
  59. return e.data.guarded;
  60. }
  61. if (view && view.cell && model_1.Cell.isCell(view.cell)) {
  62. return false;
  63. }
  64. if (this.svg === e.target ||
  65. this.container === e.target ||
  66. this.svg.contains(e.target)) {
  67. return false;
  68. }
  69. return true;
  70. }
  71. findView(elem) {
  72. return this.graph.findViewByElem(elem);
  73. }
  74. onDblClick(evt) {
  75. if (this.options.preventDefaultDblClick) {
  76. evt.preventDefault();
  77. }
  78. const e = this.normalizeEvent(evt);
  79. const view = this.findView(e.target);
  80. if (this.guard(e, view)) {
  81. return;
  82. }
  83. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  84. if (view) {
  85. view.onDblClick(e, localPoint.x, localPoint.y);
  86. }
  87. else {
  88. this.graph.trigger('blank:dblclick', {
  89. e,
  90. x: localPoint.x,
  91. y: localPoint.y,
  92. });
  93. }
  94. }
  95. onClick(evt) {
  96. if (this.getMouseMovedCount(evt) <= this.options.clickThreshold) {
  97. const e = this.normalizeEvent(evt);
  98. const view = this.findView(e.target);
  99. if (this.guard(e, view)) {
  100. return;
  101. }
  102. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  103. if (view) {
  104. view.onClick(e, localPoint.x, localPoint.y);
  105. }
  106. else {
  107. this.graph.trigger('blank:click', {
  108. e,
  109. x: localPoint.x,
  110. y: localPoint.y,
  111. });
  112. }
  113. }
  114. }
  115. isPreventDefaultContextMenu(view) {
  116. let preventDefaultContextMenu = this.options.preventDefaultContextMenu;
  117. if (typeof preventDefaultContextMenu === 'function') {
  118. preventDefaultContextMenu = x6_common_1.FunctionExt.call(preventDefaultContextMenu, this.graph, { view });
  119. }
  120. return preventDefaultContextMenu;
  121. }
  122. onContextMenu(evt) {
  123. const e = this.normalizeEvent(evt);
  124. const view = this.findView(e.target);
  125. if (this.isPreventDefaultContextMenu(view)) {
  126. evt.preventDefault();
  127. }
  128. if (this.guard(e, view)) {
  129. return;
  130. }
  131. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  132. if (view) {
  133. view.onContextMenu(e, localPoint.x, localPoint.y);
  134. }
  135. else {
  136. this.graph.trigger('blank:contextmenu', {
  137. e,
  138. x: localPoint.x,
  139. y: localPoint.y,
  140. });
  141. }
  142. }
  143. delegateDragEvents(e, view) {
  144. if (e.data == null) {
  145. e.data = {};
  146. }
  147. this.setEventData(e, {
  148. currentView: view || null,
  149. mouseMovedCount: 0,
  150. startPosition: {
  151. x: e.clientX,
  152. y: e.clientY,
  153. },
  154. });
  155. const ctor = this.constructor;
  156. this.delegateDocumentEvents(ctor.documentEvents, e.data);
  157. this.undelegateEvents();
  158. }
  159. getMouseMovedCount(e) {
  160. const data = this.getEventData(e);
  161. return data.mouseMovedCount || 0;
  162. }
  163. onMouseDown(evt) {
  164. const e = this.normalizeEvent(evt);
  165. const view = this.findView(e.target);
  166. if (this.guard(e, view)) {
  167. return;
  168. }
  169. if (this.options.preventDefaultMouseDown) {
  170. evt.preventDefault();
  171. }
  172. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  173. if (view) {
  174. view.onMouseDown(e, localPoint.x, localPoint.y);
  175. }
  176. else {
  177. if (this.options.preventDefaultBlankAction &&
  178. ['touchstart'].includes(e.type)) {
  179. evt.preventDefault();
  180. }
  181. this.graph.trigger('blank:mousedown', {
  182. e,
  183. x: localPoint.x,
  184. y: localPoint.y,
  185. });
  186. }
  187. this.delegateDragEvents(e, view);
  188. }
  189. onMouseMove(evt) {
  190. const data = this.getEventData(evt);
  191. const startPosition = data.startPosition;
  192. if (startPosition &&
  193. startPosition.x === evt.clientX &&
  194. startPosition.y === evt.clientY) {
  195. return;
  196. }
  197. if (data.mouseMovedCount == null) {
  198. data.mouseMovedCount = 0;
  199. }
  200. data.mouseMovedCount += 1;
  201. const mouseMovedCount = data.mouseMovedCount;
  202. if (mouseMovedCount <= this.options.moveThreshold) {
  203. return;
  204. }
  205. const e = this.normalizeEvent(evt);
  206. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  207. const view = data.currentView;
  208. if (view) {
  209. view.onMouseMove(e, localPoint.x, localPoint.y);
  210. }
  211. else {
  212. this.graph.trigger('blank:mousemove', {
  213. e,
  214. x: localPoint.x,
  215. y: localPoint.y,
  216. });
  217. }
  218. this.setEventData(e, data);
  219. }
  220. onMouseUp(e) {
  221. this.undelegateDocumentEvents();
  222. const normalized = this.normalizeEvent(e);
  223. const localPoint = this.graph.snapToGrid(normalized.clientX, normalized.clientY);
  224. const data = this.getEventData(e);
  225. const view = data.currentView;
  226. if (view) {
  227. view.onMouseUp(normalized, localPoint.x, localPoint.y);
  228. }
  229. else {
  230. this.graph.trigger('blank:mouseup', {
  231. e: normalized,
  232. x: localPoint.x,
  233. y: localPoint.y,
  234. });
  235. }
  236. if (!e.isPropagationStopped()) {
  237. const ev = new x6_common_1.Dom.EventObject(e, {
  238. type: 'click',
  239. data: e.data,
  240. });
  241. this.onClick(ev);
  242. }
  243. e.stopImmediatePropagation();
  244. this.delegateEvents();
  245. }
  246. onMouseOver(evt) {
  247. const e = this.normalizeEvent(evt);
  248. const view = this.findView(e.target);
  249. if (this.guard(e, view)) {
  250. return;
  251. }
  252. if (view) {
  253. view.onMouseOver(e);
  254. }
  255. else {
  256. // prevent border of paper from triggering this
  257. if (this.container === e.target) {
  258. return;
  259. }
  260. this.graph.trigger('blank:mouseover', { e });
  261. }
  262. }
  263. onMouseOut(evt) {
  264. const e = this.normalizeEvent(evt);
  265. const view = this.findView(e.target);
  266. if (this.guard(e, view)) {
  267. return;
  268. }
  269. if (view) {
  270. view.onMouseOut(e);
  271. }
  272. else {
  273. if (this.container === e.target) {
  274. return;
  275. }
  276. this.graph.trigger('blank:mouseout', { e });
  277. }
  278. }
  279. onMouseEnter(evt) {
  280. const e = this.normalizeEvent(evt);
  281. const view = this.findView(e.target);
  282. if (this.guard(e, view)) {
  283. return;
  284. }
  285. const relatedView = this.graph.findViewByElem(e.relatedTarget);
  286. if (view) {
  287. if (relatedView === view) {
  288. // mouse moved from tool to view
  289. return;
  290. }
  291. view.onMouseEnter(e);
  292. }
  293. else {
  294. if (relatedView) {
  295. return;
  296. }
  297. this.graph.trigger('graph:mouseenter', { e });
  298. }
  299. }
  300. onMouseLeave(evt) {
  301. const e = this.normalizeEvent(evt);
  302. const view = this.findView(e.target);
  303. if (this.guard(e, view)) {
  304. return;
  305. }
  306. const relatedView = this.graph.findViewByElem(e.relatedTarget);
  307. if (view) {
  308. if (relatedView === view) {
  309. // mouse moved from view to tool
  310. return;
  311. }
  312. view.onMouseLeave(e);
  313. }
  314. else {
  315. if (relatedView) {
  316. return;
  317. }
  318. this.graph.trigger('graph:mouseleave', { e });
  319. }
  320. }
  321. onMouseWheel(evt) {
  322. const e = this.normalizeEvent(evt);
  323. const view = this.findView(e.target);
  324. if (this.guard(e, view)) {
  325. return;
  326. }
  327. const originalEvent = e.originalEvent;
  328. const localPoint = this.graph.snapToGrid(originalEvent.clientX, originalEvent.clientY);
  329. const delta = Math.max(-1, Math.min(1, originalEvent.wheelDelta || -originalEvent.detail));
  330. if (view) {
  331. view.onMouseWheel(e, localPoint.x, localPoint.y, delta);
  332. }
  333. else {
  334. this.graph.trigger('blank:mousewheel', {
  335. e,
  336. delta,
  337. x: localPoint.x,
  338. y: localPoint.y,
  339. });
  340. }
  341. }
  342. onCustomEvent(evt) {
  343. const elem = evt.currentTarget;
  344. const event = elem.getAttribute('event') || elem.getAttribute('data-event');
  345. if (event) {
  346. const view = this.findView(elem);
  347. if (view) {
  348. const e = this.normalizeEvent(evt);
  349. if (this.guard(e, view)) {
  350. return;
  351. }
  352. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  353. view.onCustomEvent(e, event, localPoint.x, localPoint.y);
  354. }
  355. }
  356. }
  357. handleMagnetEvent(evt, handler) {
  358. const magnetElem = evt.currentTarget;
  359. const magnetValue = magnetElem.getAttribute('magnet');
  360. if (magnetValue && magnetValue.toLowerCase() !== 'false') {
  361. const view = this.findView(magnetElem);
  362. if (view) {
  363. const e = this.normalizeEvent(evt);
  364. if (this.guard(e, view)) {
  365. return;
  366. }
  367. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  368. x6_common_1.FunctionExt.call(handler, this.graph, view, e, magnetElem, localPoint.x, localPoint.y);
  369. }
  370. }
  371. }
  372. onMagnetMouseDown(e) {
  373. this.handleMagnetEvent(e, (view, e, magnet, x, y) => {
  374. view.onMagnetMouseDown(e, magnet, x, y);
  375. });
  376. }
  377. onMagnetDblClick(e) {
  378. this.handleMagnetEvent(e, (view, e, magnet, x, y) => {
  379. view.onMagnetDblClick(e, magnet, x, y);
  380. });
  381. }
  382. onMagnetContextMenu(e) {
  383. const view = this.findView(e.target);
  384. if (this.isPreventDefaultContextMenu(view)) {
  385. e.preventDefault();
  386. }
  387. this.handleMagnetEvent(e, (view, e, magnet, x, y) => {
  388. view.onMagnetContextMenu(e, magnet, x, y);
  389. });
  390. }
  391. onLabelMouseDown(evt) {
  392. const labelNode = evt.currentTarget;
  393. const view = this.findView(labelNode);
  394. if (view) {
  395. const e = this.normalizeEvent(evt);
  396. if (this.guard(e, view)) {
  397. return;
  398. }
  399. const localPoint = this.graph.snapToGrid(e.clientX, e.clientY);
  400. view.onLabelMouseDown(e, localPoint.x, localPoint.y);
  401. }
  402. }
  403. onImageDragStart() {
  404. // This is the only way to prevent image dragging in Firefox that works.
  405. // Setting -moz-user-select: none, draggable="false" attribute or
  406. // user-drag: none didn't help.
  407. return false;
  408. }
  409. dispose() {
  410. this.undelegateEvents();
  411. this.undelegateDocumentEvents();
  412. this.restore();
  413. this.restore = () => { };
  414. }
  415. }
  416. __decorate([
  417. view_1.View.dispose()
  418. ], GraphView.prototype, "dispose", null);
  419. exports.GraphView = GraphView;
  420. (function (GraphView) {
  421. const prefixCls = `${config_1.Config.prefixCls}-graph`;
  422. GraphView.markup = [
  423. {
  424. ns: x6_common_1.Dom.ns.xhtml,
  425. tagName: 'div',
  426. selector: 'background',
  427. className: `${prefixCls}-background`,
  428. },
  429. {
  430. ns: x6_common_1.Dom.ns.xhtml,
  431. tagName: 'div',
  432. selector: 'grid',
  433. className: `${prefixCls}-grid`,
  434. },
  435. {
  436. ns: x6_common_1.Dom.ns.svg,
  437. tagName: 'svg',
  438. selector: 'svg',
  439. className: `${prefixCls}-svg`,
  440. attrs: {
  441. width: '100%',
  442. height: '100%',
  443. 'xmlns:xlink': x6_common_1.Dom.ns.xlink,
  444. },
  445. children: [
  446. {
  447. tagName: 'defs',
  448. selector: 'defs',
  449. },
  450. {
  451. tagName: 'g',
  452. selector: 'viewport',
  453. className: `${prefixCls}-svg-viewport`,
  454. children: [
  455. {
  456. tagName: 'g',
  457. selector: 'primer',
  458. className: `${prefixCls}-svg-primer`,
  459. },
  460. {
  461. tagName: 'g',
  462. selector: 'stage',
  463. className: `${prefixCls}-svg-stage`,
  464. },
  465. {
  466. tagName: 'g',
  467. selector: 'decorator',
  468. className: `${prefixCls}-svg-decorator`,
  469. },
  470. {
  471. tagName: 'g',
  472. selector: 'overlay',
  473. className: `${prefixCls}-svg-overlay`,
  474. },
  475. ],
  476. },
  477. ],
  478. },
  479. ];
  480. function snapshoot(elem) {
  481. const cloned = elem.cloneNode();
  482. elem.childNodes.forEach((child) => cloned.appendChild(child));
  483. return () => {
  484. // remove all children
  485. x6_common_1.Dom.empty(elem);
  486. // remove all attributes
  487. while (elem.attributes.length > 0) {
  488. elem.removeAttribute(elem.attributes[0].name);
  489. }
  490. // restore attributes
  491. for (let i = 0, l = cloned.attributes.length; i < l; i += 1) {
  492. const attr = cloned.attributes[i];
  493. elem.setAttribute(attr.name, attr.value);
  494. }
  495. // restore children
  496. cloned.childNodes.forEach((child) => elem.appendChild(child));
  497. };
  498. }
  499. GraphView.snapshoot = snapshoot;
  500. })(GraphView = exports.GraphView || (exports.GraphView = {}));
  501. (function (GraphView) {
  502. const prefixCls = config_1.Config.prefixCls;
  503. GraphView.events = {
  504. dblclick: 'onDblClick',
  505. contextmenu: 'onContextMenu',
  506. touchstart: 'onMouseDown',
  507. mousedown: 'onMouseDown',
  508. mouseover: 'onMouseOver',
  509. mouseout: 'onMouseOut',
  510. mouseenter: 'onMouseEnter',
  511. mouseleave: 'onMouseLeave',
  512. mousewheel: 'onMouseWheel',
  513. DOMMouseScroll: 'onMouseWheel',
  514. [`mouseenter .${prefixCls}-cell`]: 'onMouseEnter',
  515. [`mouseleave .${prefixCls}-cell`]: 'onMouseLeave',
  516. [`mouseenter .${prefixCls}-cell-tools`]: 'onMouseEnter',
  517. [`mouseleave .${prefixCls}-cell-tools`]: 'onMouseLeave',
  518. [`mousedown .${prefixCls}-cell [event]`]: 'onCustomEvent',
  519. [`touchstart .${prefixCls}-cell [event]`]: 'onCustomEvent',
  520. [`mousedown .${prefixCls}-cell [data-event]`]: 'onCustomEvent',
  521. [`touchstart .${prefixCls}-cell [data-event]`]: 'onCustomEvent',
  522. [`dblclick .${prefixCls}-cell [magnet]`]: 'onMagnetDblClick',
  523. [`contextmenu .${prefixCls}-cell [magnet]`]: 'onMagnetContextMenu',
  524. [`mousedown .${prefixCls}-cell [magnet]`]: 'onMagnetMouseDown',
  525. [`touchstart .${prefixCls}-cell [magnet]`]: 'onMagnetMouseDown',
  526. [`dblclick .${prefixCls}-cell [data-magnet]`]: 'onMagnetDblClick',
  527. [`contextmenu .${prefixCls}-cell [data-magnet]`]: 'onMagnetContextMenu',
  528. [`mousedown .${prefixCls}-cell [data-magnet]`]: 'onMagnetMouseDown',
  529. [`touchstart .${prefixCls}-cell [data-magnet]`]: 'onMagnetMouseDown',
  530. [`dragstart .${prefixCls}-cell image`]: 'onImageDragStart',
  531. [`mousedown .${prefixCls}-edge .${prefixCls}-edge-label`]: 'onLabelMouseDown',
  532. [`touchstart .${prefixCls}-edge .${prefixCls}-edge-label`]: 'onLabelMouseDown',
  533. };
  534. GraphView.documentEvents = {
  535. mousemove: 'onMouseMove',
  536. touchmove: 'onMouseMove',
  537. mouseup: 'onMouseUp',
  538. touchend: 'onMouseUp',
  539. touchcancel: 'onMouseUp',
  540. };
  541. })(GraphView = exports.GraphView || (exports.GraphView = {}));
  542. //# sourceMappingURL=view.js.map