cell.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. var __rest = (this && this.__rest) || function (s, e) {
  9. var t = {};
  10. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  11. t[p] = s[p];
  12. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  13. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  14. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  15. t[p[i]] = s[p[i]];
  16. }
  17. return t;
  18. };
  19. Object.defineProperty(exports, "__esModule", { value: true });
  20. exports.CellView = void 0;
  21. /* eslint-disable @typescript-eslint/no-unused-vars */
  22. const x6_geometry_1 = require("@antv/x6-geometry");
  23. const x6_common_1 = require("@antv/x6-common");
  24. const registry_1 = require("../registry/registry");
  25. const view_1 = require("./view");
  26. const cache_1 = require("./cache");
  27. const markup_1 = require("./markup");
  28. const tool_1 = require("./tool");
  29. const attr_1 = require("./attr");
  30. const flag_1 = require("./flag");
  31. const util_1 = require("../util");
  32. class CellView extends view_1.View {
  33. static getDefaults() {
  34. return this.defaults;
  35. }
  36. static config(options) {
  37. this.defaults = this.getOptions(options);
  38. }
  39. static getOptions(options) {
  40. const mergeActions = (arr1, arr2) => {
  41. if (arr2 != null) {
  42. return x6_common_1.ArrayExt.uniq([
  43. ...(Array.isArray(arr1) ? arr1 : [arr1]),
  44. ...(Array.isArray(arr2) ? arr2 : [arr2]),
  45. ]);
  46. }
  47. return Array.isArray(arr1) ? [...arr1] : [arr1];
  48. };
  49. const ret = x6_common_1.ObjectExt.cloneDeep(this.getDefaults());
  50. const { bootstrap, actions, events, documentEvents } = options, others = __rest(options, ["bootstrap", "actions", "events", "documentEvents"]);
  51. if (bootstrap) {
  52. ret.bootstrap = mergeActions(ret.bootstrap, bootstrap);
  53. }
  54. if (actions) {
  55. Object.entries(actions).forEach(([key, val]) => {
  56. const raw = ret.actions[key];
  57. if (val && raw) {
  58. ret.actions[key] = mergeActions(raw, val);
  59. }
  60. else if (val) {
  61. ret.actions[key] = mergeActions(val);
  62. }
  63. });
  64. }
  65. if (events) {
  66. ret.events = Object.assign(Object.assign({}, ret.events), events);
  67. }
  68. if (options.documentEvents) {
  69. ret.documentEvents = Object.assign(Object.assign({}, ret.documentEvents), documentEvents);
  70. }
  71. return x6_common_1.ObjectExt.merge(ret, others);
  72. }
  73. get [Symbol.toStringTag]() {
  74. return CellView.toStringTag;
  75. }
  76. constructor(cell, options = {}) {
  77. super();
  78. this.cell = cell;
  79. this.options = this.ensureOptions(options);
  80. this.graph = this.options.graph;
  81. this.attr = new attr_1.AttrManager(this);
  82. this.flag = new flag_1.FlagManager(this, this.options.actions, this.options.bootstrap);
  83. this.cache = new cache_1.Cache(this);
  84. this.setContainer(this.ensureContainer());
  85. this.setup();
  86. this.init();
  87. }
  88. init() { }
  89. onRemove() {
  90. this.removeTools();
  91. }
  92. get priority() {
  93. return this.options.priority;
  94. }
  95. get rootSelector() {
  96. return this.options.rootSelector;
  97. }
  98. getConstructor() {
  99. return this.constructor;
  100. }
  101. ensureOptions(options) {
  102. return this.getConstructor().getOptions(options);
  103. }
  104. getContainerTagName() {
  105. return this.options.isSvgElement ? 'g' : 'div';
  106. }
  107. getContainerStyle() { }
  108. getContainerAttrs() {
  109. return {
  110. 'data-cell-id': this.cell.id,
  111. 'data-shape': this.cell.shape,
  112. };
  113. }
  114. getContainerClassName() {
  115. return this.prefixClassName('cell');
  116. }
  117. ensureContainer() {
  118. return view_1.View.createElement(this.getContainerTagName(), this.options.isSvgElement);
  119. }
  120. setContainer(container) {
  121. if (this.container !== container) {
  122. this.undelegateEvents();
  123. this.container = container;
  124. if (this.options.events != null) {
  125. this.delegateEvents(this.options.events);
  126. }
  127. const attrs = this.getContainerAttrs();
  128. if (attrs != null) {
  129. this.setAttrs(attrs, container);
  130. }
  131. const style = this.getContainerStyle();
  132. if (style != null) {
  133. this.setStyle(style, container);
  134. }
  135. const className = this.getContainerClassName();
  136. if (className != null) {
  137. this.addClass(className, container);
  138. }
  139. }
  140. return this;
  141. }
  142. isNodeView() {
  143. return false;
  144. }
  145. isEdgeView() {
  146. return false;
  147. }
  148. render() {
  149. return this;
  150. }
  151. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  152. confirmUpdate(flag, options = {}) {
  153. return 0;
  154. }
  155. getBootstrapFlag() {
  156. return this.flag.getBootstrapFlag();
  157. }
  158. getFlag(actions) {
  159. return this.flag.getFlag(actions);
  160. }
  161. hasAction(flag, actions) {
  162. return this.flag.hasAction(flag, actions);
  163. }
  164. removeAction(flag, actions) {
  165. return this.flag.removeAction(flag, actions);
  166. }
  167. handleAction(flag, action, handle, additionalRemovedActions) {
  168. if (this.hasAction(flag, action)) {
  169. handle();
  170. const removedFlags = [action];
  171. if (additionalRemovedActions) {
  172. if (typeof additionalRemovedActions === 'string') {
  173. removedFlags.push(additionalRemovedActions);
  174. }
  175. else {
  176. removedFlags.push(...additionalRemovedActions);
  177. }
  178. }
  179. return this.removeAction(flag, removedFlags);
  180. }
  181. return flag;
  182. }
  183. setup() {
  184. this.cell.on('changed', this.onCellChanged, this);
  185. }
  186. onCellChanged({ options }) {
  187. this.onAttrsChange(options);
  188. }
  189. onAttrsChange(options) {
  190. let flag = this.flag.getChangedFlag();
  191. if (options.updated || !flag) {
  192. return;
  193. }
  194. if (options.dirty && this.hasAction(flag, 'update')) {
  195. flag |= this.getFlag('render'); // eslint-disable-line no-bitwise
  196. }
  197. // tool changes should be sync render
  198. if (options.toolId) {
  199. options.async = false;
  200. }
  201. if (this.graph != null) {
  202. this.graph.renderer.requestViewUpdate(this, flag, options);
  203. }
  204. }
  205. parseJSONMarkup(markup, rootElem) {
  206. const result = markup_1.Markup.parseJSONMarkup(markup);
  207. const selectors = result.selectors;
  208. const rootSelector = this.rootSelector;
  209. if (rootElem && rootSelector) {
  210. if (selectors[rootSelector]) {
  211. throw new Error('Invalid root selector');
  212. }
  213. selectors[rootSelector] = rootElem;
  214. }
  215. return result;
  216. }
  217. can(feature) {
  218. let interacting = this.graph.options.interacting;
  219. if (typeof interacting === 'function') {
  220. interacting = x6_common_1.FunctionExt.call(interacting, this.graph, this);
  221. }
  222. if (typeof interacting === 'object') {
  223. let val = interacting[feature];
  224. if (typeof val === 'function') {
  225. val = x6_common_1.FunctionExt.call(val, this.graph, this);
  226. }
  227. return val !== false;
  228. }
  229. if (typeof interacting === 'boolean') {
  230. return interacting;
  231. }
  232. return false;
  233. }
  234. cleanCache() {
  235. this.cache.clean();
  236. return this;
  237. }
  238. getCache(elem) {
  239. return this.cache.get(elem);
  240. }
  241. getDataOfElement(elem) {
  242. return this.cache.getData(elem);
  243. }
  244. getMatrixOfElement(elem) {
  245. return this.cache.getMatrix(elem);
  246. }
  247. getShapeOfElement(elem) {
  248. return this.cache.getShape(elem);
  249. }
  250. getBoundingRectOfElement(elem) {
  251. return this.cache.getBoundingRect(elem);
  252. }
  253. getBBoxOfElement(elem) {
  254. const rect = this.getBoundingRectOfElement(elem);
  255. const matrix = this.getMatrixOfElement(elem);
  256. const rm = this.getRootRotatedMatrix();
  257. const tm = this.getRootTranslatedMatrix();
  258. return util_1.Util.transformRectangle(rect, tm.multiply(rm).multiply(matrix));
  259. }
  260. getUnrotatedBBoxOfElement(elem) {
  261. const rect = this.getBoundingRectOfElement(elem);
  262. const matrix = this.getMatrixOfElement(elem);
  263. const tm = this.getRootTranslatedMatrix();
  264. return util_1.Util.transformRectangle(rect, tm.multiply(matrix));
  265. }
  266. getBBox(options = {}) {
  267. let bbox;
  268. if (options.useCellGeometry) {
  269. const cell = this.cell;
  270. const angle = cell.isNode() ? cell.getAngle() : 0;
  271. bbox = cell.getBBox().bbox(angle);
  272. }
  273. else {
  274. bbox = this.getBBoxOfElement(this.container);
  275. }
  276. return this.graph.coord.localToGraphRect(bbox);
  277. }
  278. getRootTranslatedMatrix() {
  279. const cell = this.cell;
  280. const pos = cell.isNode() ? cell.getPosition() : { x: 0, y: 0 };
  281. return x6_common_1.Dom.createSVGMatrix().translate(pos.x, pos.y);
  282. }
  283. getRootRotatedMatrix() {
  284. let matrix = x6_common_1.Dom.createSVGMatrix();
  285. const cell = this.cell;
  286. const angle = cell.isNode() ? cell.getAngle() : 0;
  287. if (angle) {
  288. const bbox = cell.getBBox();
  289. const cx = bbox.width / 2;
  290. const cy = bbox.height / 2;
  291. matrix = matrix.translate(cx, cy).rotate(angle).translate(-cx, -cy);
  292. }
  293. return matrix;
  294. }
  295. findMagnet(elem = this.container) {
  296. return this.findByAttr('magnet', elem);
  297. }
  298. updateAttrs(rootNode, attrs, options = {}) {
  299. if (options.rootBBox == null) {
  300. options.rootBBox = new x6_geometry_1.Rectangle();
  301. }
  302. if (options.selectors == null) {
  303. options.selectors = this.selectors;
  304. }
  305. this.attr.update(rootNode, attrs, options);
  306. }
  307. isEdgeElement(magnet) {
  308. return this.cell.isEdge() && (magnet == null || magnet === this.container);
  309. }
  310. // #region highlight
  311. prepareHighlight(elem, options = {}) {
  312. const magnet = elem || this.container;
  313. options.partial = magnet === this.container;
  314. return magnet;
  315. }
  316. highlight(elem, options = {}) {
  317. const magnet = this.prepareHighlight(elem, options);
  318. this.notify('cell:highlight', {
  319. magnet,
  320. options,
  321. view: this,
  322. cell: this.cell,
  323. });
  324. if (this.isEdgeView()) {
  325. this.notify('edge:highlight', {
  326. magnet,
  327. options,
  328. view: this,
  329. edge: this.cell,
  330. cell: this.cell,
  331. });
  332. }
  333. else if (this.isNodeView()) {
  334. this.notify('node:highlight', {
  335. magnet,
  336. options,
  337. view: this,
  338. node: this.cell,
  339. cell: this.cell,
  340. });
  341. }
  342. return this;
  343. }
  344. unhighlight(elem, options = {}) {
  345. const magnet = this.prepareHighlight(elem, options);
  346. this.notify('cell:unhighlight', {
  347. magnet,
  348. options,
  349. view: this,
  350. cell: this.cell,
  351. });
  352. if (this.isNodeView()) {
  353. this.notify('node:unhighlight', {
  354. magnet,
  355. options,
  356. view: this,
  357. node: this.cell,
  358. cell: this.cell,
  359. });
  360. }
  361. else if (this.isEdgeView()) {
  362. this.notify('edge:unhighlight', {
  363. magnet,
  364. options,
  365. view: this,
  366. edge: this.cell,
  367. cell: this.cell,
  368. });
  369. }
  370. return this;
  371. }
  372. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  373. notifyUnhighlight(magnet, options) { }
  374. // #endregion
  375. getEdgeTerminal(magnet, x, y, edge, type) {
  376. const cell = this.cell;
  377. const portId = this.findAttr('port', magnet);
  378. const selector = magnet.getAttribute('data-selector');
  379. const terminal = { cell: cell.id };
  380. if (selector != null) {
  381. terminal.magnet = selector;
  382. }
  383. if (portId != null) {
  384. terminal.port = portId;
  385. if (cell.isNode()) {
  386. if (!cell.hasPort(portId) && selector == null) {
  387. // port created via the `port` attribute (not API)
  388. terminal.selector = this.getSelector(magnet);
  389. }
  390. }
  391. }
  392. else if (selector == null && this.container !== magnet) {
  393. terminal.selector = this.getSelector(magnet);
  394. }
  395. return terminal;
  396. }
  397. getMagnetFromEdgeTerminal(terminal) {
  398. const cell = this.cell;
  399. const root = this.container;
  400. const portId = terminal.port;
  401. let selector = terminal.magnet;
  402. let magnet;
  403. if (portId != null && cell.isNode() && cell.hasPort(portId)) {
  404. magnet = this.findPortElem(portId, selector) || root;
  405. }
  406. else {
  407. if (!selector) {
  408. selector = terminal.selector;
  409. }
  410. if (!selector && portId != null) {
  411. selector = `[port="${portId}"]`;
  412. }
  413. magnet = this.findOne(selector, root, this.selectors);
  414. }
  415. return magnet;
  416. }
  417. hasTools(name) {
  418. const tools = this.tools;
  419. if (tools == null) {
  420. return false;
  421. }
  422. if (name == null) {
  423. return true;
  424. }
  425. return tools.name === name;
  426. }
  427. addTools(config) {
  428. this.removeTools();
  429. if (config) {
  430. if (!this.can('toolsAddable')) {
  431. return this;
  432. }
  433. const tools = tool_1.ToolsView.isToolsView(config)
  434. ? config
  435. : new tool_1.ToolsView(config);
  436. this.tools = tools;
  437. tools.config({ view: this });
  438. tools.mount();
  439. }
  440. return this;
  441. }
  442. updateTools(options = {}) {
  443. if (this.tools) {
  444. this.tools.update(options);
  445. }
  446. return this;
  447. }
  448. removeTools() {
  449. if (this.tools) {
  450. this.tools.remove();
  451. this.tools = null;
  452. }
  453. return this;
  454. }
  455. hideTools() {
  456. if (this.tools) {
  457. this.tools.hide();
  458. }
  459. return this;
  460. }
  461. showTools() {
  462. if (this.tools) {
  463. this.tools.show();
  464. }
  465. return this;
  466. }
  467. renderTools() {
  468. const tools = this.cell.getTools();
  469. this.addTools(tools);
  470. return this;
  471. }
  472. notify(name, args) {
  473. this.trigger(name, args);
  474. this.graph.trigger(name, args);
  475. return this;
  476. }
  477. getEventArgs(e, x, y) {
  478. const view = this; // eslint-disable-line @typescript-eslint/no-this-alias
  479. const cell = view.cell;
  480. if (x == null || y == null) {
  481. return { e, view, cell };
  482. }
  483. return { e, x, y, view, cell };
  484. }
  485. onClick(e, x, y) {
  486. this.notify('cell:click', this.getEventArgs(e, x, y));
  487. }
  488. onDblClick(e, x, y) {
  489. this.notify('cell:dblclick', this.getEventArgs(e, x, y));
  490. }
  491. onContextMenu(e, x, y) {
  492. this.notify('cell:contextmenu', this.getEventArgs(e, x, y));
  493. }
  494. onMouseDown(e, x, y) {
  495. if (this.cell.model) {
  496. this.cachedModelForMouseEvent = this.cell.model;
  497. this.cachedModelForMouseEvent.startBatch('mouse');
  498. }
  499. this.notify('cell:mousedown', this.getEventArgs(e, x, y));
  500. }
  501. onMouseUp(e, x, y) {
  502. this.notify('cell:mouseup', this.getEventArgs(e, x, y));
  503. if (this.cachedModelForMouseEvent) {
  504. this.cachedModelForMouseEvent.stopBatch('mouse', { cell: this.cell });
  505. this.cachedModelForMouseEvent = null;
  506. }
  507. }
  508. onMouseMove(e, x, y) {
  509. this.notify('cell:mousemove', this.getEventArgs(e, x, y));
  510. }
  511. onMouseOver(e) {
  512. this.notify('cell:mouseover', this.getEventArgs(e));
  513. }
  514. onMouseOut(e) {
  515. this.notify('cell:mouseout', this.getEventArgs(e));
  516. }
  517. onMouseEnter(e) {
  518. this.notify('cell:mouseenter', this.getEventArgs(e));
  519. }
  520. onMouseLeave(e) {
  521. this.notify('cell:mouseleave', this.getEventArgs(e));
  522. }
  523. onMouseWheel(e, x, y, delta) {
  524. this.notify('cell:mousewheel', Object.assign({ delta }, this.getEventArgs(e, x, y)));
  525. }
  526. onCustomEvent(e, name, x, y) {
  527. this.notify('cell:customevent', Object.assign({ name }, this.getEventArgs(e, x, y)));
  528. this.notify(name, Object.assign({}, this.getEventArgs(e, x, y)));
  529. }
  530. onMagnetMouseDown(e, magnet, x, y) { }
  531. onMagnetDblClick(e, magnet, x, y) { }
  532. onMagnetContextMenu(e, magnet, x, y) { }
  533. onLabelMouseDown(e, x, y) { }
  534. checkMouseleave(e) {
  535. const target = this.getEventTarget(e, { fromPoint: true });
  536. const view = this.graph.findViewByElem(target);
  537. if (view === this) {
  538. return;
  539. }
  540. // Leaving the current view
  541. this.onMouseLeave(e);
  542. if (!view) {
  543. return;
  544. }
  545. // Entering another view
  546. view.onMouseEnter(e);
  547. }
  548. dispose() {
  549. this.cell.off('changed', this.onCellChanged, this);
  550. }
  551. }
  552. CellView.defaults = {
  553. isSvgElement: true,
  554. rootSelector: 'root',
  555. priority: 0,
  556. bootstrap: [],
  557. actions: {},
  558. };
  559. __decorate([
  560. CellView.dispose()
  561. ], CellView.prototype, "dispose", null);
  562. exports.CellView = CellView;
  563. (function (CellView) {
  564. CellView.Flag = flag_1.FlagManager;
  565. CellView.Attr = attr_1.AttrManager;
  566. })(CellView = exports.CellView || (exports.CellView = {}));
  567. (function (CellView) {
  568. CellView.toStringTag = `X6.${CellView.name}`;
  569. function isCellView(instance) {
  570. if (instance == null) {
  571. return false;
  572. }
  573. if (instance instanceof CellView) {
  574. return true;
  575. }
  576. const tag = instance[Symbol.toStringTag];
  577. const view = instance;
  578. if ((tag == null || tag === CellView.toStringTag) &&
  579. typeof view.isNodeView === 'function' &&
  580. typeof view.isEdgeView === 'function' &&
  581. typeof view.confirmUpdate === 'function') {
  582. return true;
  583. }
  584. return false;
  585. }
  586. CellView.isCellView = isCellView;
  587. })(CellView = exports.CellView || (exports.CellView = {}));
  588. // decorators
  589. // ----
  590. (function (CellView) {
  591. function priority(value) {
  592. return function (ctor) {
  593. ctor.config({ priority: value });
  594. };
  595. }
  596. CellView.priority = priority;
  597. function bootstrap(actions) {
  598. return function (ctor) {
  599. ctor.config({ bootstrap: actions });
  600. };
  601. }
  602. CellView.bootstrap = bootstrap;
  603. })(CellView = exports.CellView || (exports.CellView = {}));
  604. (function (CellView) {
  605. CellView.registry = registry_1.Registry.create({
  606. type: 'view',
  607. });
  608. })(CellView = exports.CellView || (exports.CellView = {}));
  609. //# sourceMappingURL=cell.js.map