group-component.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. import { __assign, __extends, __rest } from "tslib";
  2. import { difference, each, isNil, keys, mix, pick } from '@antv/util';
  3. import { propagationDelegate } from '../util/event';
  4. import { applyMatrix2BBox, getMatrixByTranslate } from '../util/matrix';
  5. import { getBBoxWithClip, updateClip } from '../util/util';
  6. import Component from './component';
  7. var STATUS_UPDATE = 'update_status';
  8. var COPY_PROPERTIES = ['visible', 'tip', 'delegateObject']; // 更新对象时需要复制的属性
  9. var COPY_PROPERTIES_EXCLUDES = ['container', 'group', 'shapesMap', 'isRegister', 'isUpdating', 'destroyed']; // 更新子组件时排除的属性
  10. var GroupComponent = /** @class */ (function (_super) {
  11. __extends(GroupComponent, _super);
  12. function GroupComponent() {
  13. return _super !== null && _super.apply(this, arguments) || this;
  14. }
  15. GroupComponent.prototype.getDefaultCfg = function () {
  16. var cfg = _super.prototype.getDefaultCfg.call(this);
  17. return __assign(__assign({}, cfg), { container: null,
  18. /**
  19. * @private
  20. * 缓存图形的 Map
  21. */
  22. shapesMap: {}, group: null, capture: true,
  23. /**
  24. * @private 组件或者图形是否允许注册
  25. * @type {false}
  26. */
  27. isRegister: false,
  28. /**
  29. * @private 是否正在更新
  30. * @type {false}
  31. */
  32. isUpdating: false,
  33. /**
  34. * @private
  35. * 是否初始状态,一旦 render,update 后,这个状态就变成 false, clear 后恢复
  36. */
  37. isInit: true });
  38. };
  39. GroupComponent.prototype.remove = function () {
  40. this.clear();
  41. var group = this.get('group');
  42. group.remove();
  43. };
  44. GroupComponent.prototype.clear = function () {
  45. var group = this.get('group');
  46. group.clear();
  47. this.set('shapesMap', {});
  48. this.clearOffScreenCache();
  49. this.set('isInit', true);
  50. };
  51. GroupComponent.prototype.getChildComponentById = function (id) {
  52. var group = this.getElementById(id);
  53. var inst = group && group.get('component');
  54. return inst;
  55. };
  56. GroupComponent.prototype.getElementById = function (id) {
  57. return this.get('shapesMap')[id];
  58. };
  59. GroupComponent.prototype.getElementByLocalId = function (localId) {
  60. var id = this.getElementId(localId);
  61. return this.getElementById(id);
  62. };
  63. GroupComponent.prototype.getElementsByName = function (name) {
  64. var rst = [];
  65. each(this.get('shapesMap'), function (elem) {
  66. if (elem.get('name') === name) {
  67. rst.push(elem);
  68. }
  69. });
  70. return rst;
  71. };
  72. GroupComponent.prototype.getContainer = function () {
  73. return this.get('container');
  74. };
  75. GroupComponent.prototype.updateInner = function (cfg) {
  76. // this.updateInner();
  77. // this.set('isUpdating', false);
  78. this.offScreenRender();
  79. if (this.get('updateAutoRender')) {
  80. this.render();
  81. }
  82. };
  83. GroupComponent.prototype.render = function () {
  84. var offScreenGroup = this.get('offScreenGroup');
  85. if (!offScreenGroup) {
  86. offScreenGroup = this.offScreenRender();
  87. }
  88. var group = this.get('group');
  89. this.updateElements(offScreenGroup, group);
  90. this.deleteElements();
  91. this.applyOffset();
  92. if (!this.get('eventInitted')) {
  93. this.initEvent();
  94. this.set('eventInitted', true);
  95. }
  96. this.set('isInit', false);
  97. };
  98. GroupComponent.prototype.show = function () {
  99. var group = this.get('group');
  100. group.show();
  101. this.set('visible', true);
  102. };
  103. GroupComponent.prototype.hide = function () {
  104. var group = this.get('group');
  105. group.hide();
  106. this.set('visible', false);
  107. };
  108. GroupComponent.prototype.setCapture = function (capture) {
  109. var group = this.get('group');
  110. group.set('capture', capture);
  111. this.set('capture', capture);
  112. };
  113. GroupComponent.prototype.destroy = function () {
  114. this.removeEvent();
  115. this.remove();
  116. _super.prototype.destroy.call(this);
  117. };
  118. GroupComponent.prototype.getBBox = function () {
  119. return this.get('group').getCanvasBBox();
  120. };
  121. GroupComponent.prototype.getLayoutBBox = function () {
  122. var group = this.get('group');
  123. // 防止被 clear 了,offScreenBBox 不存在
  124. var bbox = this.getInnerLayoutBBox();
  125. var matrix = group.getTotalMatrix();
  126. if (matrix) {
  127. bbox = applyMatrix2BBox(matrix, bbox);
  128. }
  129. return bbox; // 默认返回 getBBox,不同的组件内部单独实现
  130. };
  131. // 复写 on, off, emit 透传到 group
  132. GroupComponent.prototype.on = function (evt, callback, once) {
  133. var group = this.get('group');
  134. group.on(evt, callback, once);
  135. return this;
  136. };
  137. GroupComponent.prototype.off = function (evt, callback) {
  138. var group = this.get('group');
  139. group && group.off(evt, callback);
  140. return this;
  141. };
  142. GroupComponent.prototype.emit = function (eventName, eventObject) {
  143. var group = this.get('group');
  144. group.emit(eventName, eventObject);
  145. };
  146. GroupComponent.prototype.init = function () {
  147. _super.prototype.init.call(this);
  148. if (!this.get('group')) {
  149. this.initGroup();
  150. }
  151. this.offScreenRender(); // 绘制离屏 group
  152. };
  153. // 获取组件内部布局占的包围盒
  154. GroupComponent.prototype.getInnerLayoutBBox = function () {
  155. return this.get('offScreenBBox') || this.get('group').getBBox();
  156. };
  157. // 抛出委托对象
  158. GroupComponent.prototype.delegateEmit = function (eventName, eventObject) {
  159. var group = this.get('group');
  160. eventObject.target = group;
  161. group.emit(eventName, eventObject);
  162. propagationDelegate(group, eventName, eventObject);
  163. };
  164. // 创建离屏的 group ,不添加在 canvas 中
  165. GroupComponent.prototype.createOffScreenGroup = function () {
  166. var group = this.get('group');
  167. var GroupClass = group.getGroupBase(); // 获取分组的构造函数
  168. var newGroup = new GroupClass({
  169. delegateObject: this.getDelegateObject(),
  170. });
  171. return newGroup;
  172. };
  173. // 应用 offset
  174. GroupComponent.prototype.applyOffset = function () {
  175. var offsetX = this.get('offsetX');
  176. var offsetY = this.get('offsetY');
  177. this.moveElementTo(this.get('group'), {
  178. x: offsetX,
  179. y: offsetY,
  180. });
  181. };
  182. GroupComponent.prototype.initGroup = function () {
  183. var container = this.get('container');
  184. this.set('group', container.addGroup({
  185. id: this.get('id'),
  186. name: this.get('name'),
  187. capture: this.get('capture'),
  188. visible: this.get('visible'),
  189. isComponent: true,
  190. component: this,
  191. delegateObject: this.getDelegateObject(),
  192. }));
  193. };
  194. // 离屏渲染
  195. GroupComponent.prototype.offScreenRender = function () {
  196. this.clearOffScreenCache();
  197. var offScreenGroup = this.createOffScreenGroup();
  198. this.renderInner(offScreenGroup);
  199. this.set('offScreenGroup', offScreenGroup);
  200. // 包含包围盒的 bbox
  201. this.set('offScreenBBox', getBBoxWithClip(offScreenGroup));
  202. return offScreenGroup;
  203. };
  204. /**
  205. * @protected
  206. * 在组件上添加分组,主要解决 isReigeter 的问题
  207. * @param {IGroup} parent 父元素
  208. * @param {object} cfg 分组的配置项
  209. */
  210. GroupComponent.prototype.addGroup = function (parent, cfg) {
  211. this.appendDelegateObject(parent, cfg);
  212. var group = parent.addGroup(cfg);
  213. if (this.get('isRegister')) {
  214. this.registerElement(group);
  215. }
  216. return group;
  217. };
  218. /**
  219. * @protected
  220. * 在组件上添加图形,主要解决 isReigeter 的问题
  221. * @param {IGroup} parent 父元素
  222. * @param {object} cfg 分组的配置项
  223. */
  224. GroupComponent.prototype.addShape = function (parent, cfg) {
  225. this.appendDelegateObject(parent, cfg);
  226. var shape = parent.addShape(cfg);
  227. if (this.get('isRegister')) {
  228. this.registerElement(shape);
  229. }
  230. return shape;
  231. };
  232. /**
  233. * 在组件上添加子组件
  234. *
  235. * @param parent 父元素
  236. * @param cfg 子组件配置项
  237. */
  238. GroupComponent.prototype.addComponent = function (parent, cfg) {
  239. var id = cfg.id, Ctor = cfg.component, restCfg = __rest(cfg, ["id", "component"]);
  240. // @ts-ignore
  241. var inst = new Ctor(__assign(__assign({}, restCfg), { id: id, container: parent, updateAutoRender: this.get('updateAutoRender') }));
  242. inst.init();
  243. inst.render();
  244. if (this.get('isRegister')) {
  245. this.registerElement(inst.get('group'));
  246. }
  247. return inst;
  248. };
  249. GroupComponent.prototype.initEvent = function () { };
  250. GroupComponent.prototype.removeEvent = function () {
  251. var group = this.get('group');
  252. group.off();
  253. };
  254. GroupComponent.prototype.getElementId = function (localId) {
  255. var id = this.get('id'); // 组件的 Id
  256. var name = this.get('name'); // 组件的名称
  257. return id + "-" + name + "-" + localId;
  258. };
  259. GroupComponent.prototype.registerElement = function (element) {
  260. var id = element.get('id');
  261. this.get('shapesMap')[id] = element;
  262. };
  263. GroupComponent.prototype.unregisterElement = function (element) {
  264. var id = element.get('id');
  265. delete this.get('shapesMap')[id];
  266. };
  267. // 移动元素
  268. GroupComponent.prototype.moveElementTo = function (element, point) {
  269. var matrix = getMatrixByTranslate(point);
  270. element.attr('matrix', matrix);
  271. };
  272. /**
  273. * 图形元素新出现时的动画,默认图形从透明度 0 到当前透明度
  274. * @protected
  275. * @param {string} elmentName 图形元素名称
  276. * @param {IElement} newElement 新的图形元素
  277. * @param {object} animateCfg 动画的配置项
  278. */
  279. GroupComponent.prototype.addAnimation = function (elmentName, newElement, animateCfg) {
  280. // 缓存透明度
  281. var originOpacity = newElement.attr('opacity');
  282. if (isNil(originOpacity)) {
  283. originOpacity = 1;
  284. }
  285. newElement.attr('opacity', 0);
  286. newElement.animate({ opacity: originOpacity }, animateCfg);
  287. };
  288. /**
  289. * 图形元素新出现时的动画,默认图形从透明度 0 到当前透明度
  290. * @protected
  291. * @param {string} elmentName 图形元素名称
  292. * @param {IElement} originElement 要删除的图形元素
  293. * @param {object} animateCfg 动画的配置项
  294. */
  295. GroupComponent.prototype.removeAnimation = function (elementName, originElement, animateCfg) {
  296. originElement.animate({ opacity: 0 }, animateCfg);
  297. };
  298. /**
  299. * 图形元素的更新动画
  300. * @param {string} elmentName 图形元素名称
  301. * @param {IElement} originElement 现有的图形元素
  302. * @param {object} newAttrs 新的图形元素
  303. * @param {object} animateCfg 动画的配置项
  304. */
  305. GroupComponent.prototype.updateAnimation = function (elementName, originElement, newAttrs, animateCfg) {
  306. originElement.animate(newAttrs, animateCfg);
  307. };
  308. // 更新组件的图形
  309. GroupComponent.prototype.updateElements = function (newGroup, originGroup) {
  310. var _this = this;
  311. var animate = this.get('animate');
  312. var animateOption = this.get('animateOption');
  313. var children = newGroup.getChildren().slice(0); // 创建一个新数组,防止添加到 originGroup 时, children 变动
  314. var preElement; // 前面已经匹配到的图形元素,用于
  315. each(children, function (element) {
  316. var elementId = element.get('id');
  317. var originElement = _this.getElementById(elementId);
  318. var elementName = element.get('name');
  319. if (originElement) {
  320. if (element.get('isComponent')) {
  321. // 嵌套子组件更新
  322. var childComponent = element.get('component');
  323. var origChildComponent = originElement.get('component');
  324. var newCfg = pick(childComponent.cfg, difference(keys(childComponent.cfg), COPY_PROPERTIES_EXCLUDES));
  325. origChildComponent.update(newCfg);
  326. originElement.set(STATUS_UPDATE, 'update');
  327. }
  328. else {
  329. var replaceAttrs = _this.getReplaceAttrs(originElement, element);
  330. // 更新
  331. if (animate && animateOption.update) {
  332. // 没有动画
  333. _this.updateAnimation(elementName, originElement, replaceAttrs, animateOption.update);
  334. }
  335. else {
  336. // originElement.attrs = replaceAttrs; // 直接替换
  337. originElement.attr(replaceAttrs);
  338. }
  339. // 如果是分组,则继续执行
  340. if (element.isGroup()) {
  341. _this.updateElements(element, originElement);
  342. }
  343. // 复制属性
  344. each(COPY_PROPERTIES, function (name) {
  345. originElement.set(name, element.get(name));
  346. });
  347. updateClip(originElement, element);
  348. preElement = originElement;
  349. // 执行完更新后设置状态位为更新
  350. originElement.set(STATUS_UPDATE, 'update');
  351. }
  352. }
  353. else {
  354. // 没有对应的图形,则插入当前图形
  355. originGroup.add(element); // 应该在 group 加个 insertAt 的方法
  356. var siblings = originGroup.getChildren(); // 兄弟节点
  357. siblings.splice(siblings.length - 1, 1); // 先从数组中移除,然后放到合适的位置
  358. if (preElement) {
  359. // 前面已经有更新的图形或者插入的图形,则在这个图形后面插入
  360. var index = siblings.indexOf(preElement);
  361. siblings.splice(index + 1, 0, element); // 在已经更新的图形元素后面插入
  362. }
  363. else {
  364. siblings.unshift(element);
  365. }
  366. _this.registerElement(element); // 注册节点
  367. element.set(STATUS_UPDATE, 'add'); // 执行完更新后设置状态位为添加
  368. if (element.get('isComponent')) {
  369. // 直接新增子组件container属性,实例不变
  370. var childComponent = element.get('component');
  371. childComponent.set('container', originGroup);
  372. }
  373. else if (element.isGroup()) {
  374. // 如果元素是新增加的元素,则遍历注册所有的子节点
  375. _this.registerNewGroup(element);
  376. }
  377. preElement = element;
  378. if (animate) {
  379. var animateCfg = _this.get('isInit') ? animateOption.appear : animateOption.enter;
  380. if (animateCfg) {
  381. _this.addAnimation(elementName, element, animateCfg);
  382. }
  383. }
  384. }
  385. });
  386. };
  387. GroupComponent.prototype.clearUpdateStatus = function (group) {
  388. var children = group.getChildren();
  389. each(children, function (el) {
  390. el.set(STATUS_UPDATE, null); // 清理掉更新状态
  391. });
  392. };
  393. // 清理离屏缓存
  394. GroupComponent.prototype.clearOffScreenCache = function () {
  395. var offScreenGroup = this.get('offScreenGroup');
  396. if (offScreenGroup) {
  397. // 销毁原先的离线 Group
  398. offScreenGroup.destroy();
  399. }
  400. this.set('offScreenGroup', null);
  401. this.set('offScreenBBox', null);
  402. };
  403. // private updateInner() {
  404. // const group = this.get('group');
  405. // const newGroup = this.createOffScreenGroup();
  406. // this.renderInner(newGroup);
  407. // this.applyOffset();
  408. // this.updateElements(newGroup, group);
  409. // this.deleteElements();
  410. // newGroup.destroy(); // 销毁虚拟分组
  411. // }
  412. // 获取发生委托时的对象,在事件中抛出
  413. GroupComponent.prototype.getDelegateObject = function () {
  414. var _a;
  415. var name = this.get('name');
  416. var delegateObject = (_a = {},
  417. _a[name] = this,
  418. _a.component = this,
  419. _a);
  420. return delegateObject;
  421. };
  422. // 附加委托信息,用于事件
  423. GroupComponent.prototype.appendDelegateObject = function (parent, cfg) {
  424. var parentObject = parent.get('delegateObject');
  425. if (!cfg.delegateObject) {
  426. cfg.delegateObject = {};
  427. }
  428. mix(cfg.delegateObject, parentObject); // 将父元素上的委托信息复制到自身
  429. };
  430. // 获取需要替换的属性,如果原先图形元素存在,而新图形不存在,则设置 undefined
  431. GroupComponent.prototype.getReplaceAttrs = function (originElement, newElement) {
  432. var originAttrs = originElement.attr();
  433. var newAttrs = newElement.attr();
  434. each(originAttrs, function (v, k) {
  435. if (newAttrs[k] === undefined) {
  436. newAttrs[k] = undefined;
  437. }
  438. });
  439. return newAttrs;
  440. };
  441. GroupComponent.prototype.registerNewGroup = function (group) {
  442. var _this = this;
  443. var children = group.getChildren();
  444. each(children, function (element) {
  445. _this.registerElement(element); // 注册节点
  446. element.set(STATUS_UPDATE, 'add'); // 执行完更新后设置状态位为添加
  447. if (element.isGroup()) {
  448. _this.registerNewGroup(element);
  449. }
  450. });
  451. };
  452. // 移除多余的元素
  453. GroupComponent.prototype.deleteElements = function () {
  454. var _this = this;
  455. var shapesMap = this.get('shapesMap');
  456. var deleteArray = [];
  457. // 遍历获取需要删除的图形元素
  458. each(shapesMap, function (element, id) {
  459. if (!element.get(STATUS_UPDATE) || element.destroyed) {
  460. deleteArray.push([id, element]);
  461. }
  462. else {
  463. element.set(STATUS_UPDATE, null); // 清理掉更新状态
  464. }
  465. });
  466. var animate = this.get('animate');
  467. var animateOption = this.get('animateOption');
  468. // 删除图形元素
  469. each(deleteArray, function (item) {
  470. var id = item[0], element = item[1];
  471. if (!element.destroyed) {
  472. var elementName = element.get('name');
  473. if (animate && animateOption.leave) {
  474. // 需要动画结束时移除图形
  475. var callbackAnimCfg = mix({
  476. callback: function () {
  477. _this.removeElement(element);
  478. },
  479. }, animateOption.leave);
  480. _this.removeAnimation(elementName, element, callbackAnimCfg);
  481. }
  482. else {
  483. _this.removeElement(element);
  484. }
  485. }
  486. delete shapesMap[id]; // 从缓存中移除
  487. });
  488. };
  489. GroupComponent.prototype.removeElement = function (element) {
  490. if (element.get('isGroup')) {
  491. var component = element.get('component');
  492. if (component) {
  493. component.destroy();
  494. }
  495. }
  496. element.remove();
  497. };
  498. return GroupComponent;
  499. }(Component));
  500. export default GroupComponent;
  501. //# sourceMappingURL=group-component.js.map