container.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var tslib_1 = require("tslib");
  4. var element_1 = require("./element");
  5. var util_1 = require("../util/util");
  6. var SHAPE_MAP = {};
  7. var INDEX = '_INDEX';
  8. /**
  9. * 设置 canvas
  10. * @param {IElement} element 元素
  11. * @param {ICanvas} canvas 画布
  12. */
  13. function setCanvas(element, canvas) {
  14. element.set('canvas', canvas);
  15. if (element.isGroup()) {
  16. var children = element.get('children');
  17. if (children.length) {
  18. children.forEach(function (child) {
  19. setCanvas(child, canvas);
  20. });
  21. }
  22. }
  23. }
  24. /**
  25. * 设置 timeline
  26. * @param {IElement} element 元素
  27. * @param {Timeline} timeline 时间轴
  28. */
  29. function setTimeline(element, timeline) {
  30. element.set('timeline', timeline);
  31. if (element.isGroup()) {
  32. var children = element.get('children');
  33. if (children.length) {
  34. children.forEach(function (child) {
  35. setTimeline(child, timeline);
  36. });
  37. }
  38. }
  39. }
  40. function contains(container, element) {
  41. var children = container.getChildren();
  42. return children.indexOf(element) >= 0;
  43. }
  44. function removeChild(container, element, destroy) {
  45. if (destroy === void 0) { destroy = true; }
  46. // 不再调用 element.remove() 方法,会出现循环调用
  47. if (destroy) {
  48. element.destroy();
  49. }
  50. else {
  51. element.set('parent', null);
  52. element.set('canvas', null);
  53. }
  54. util_1.removeFromArray(container.getChildren(), element);
  55. }
  56. function getComparer(compare) {
  57. return function (left, right) {
  58. var result = compare(left, right);
  59. return result === 0 ? left[INDEX] - right[INDEX] : result;
  60. };
  61. }
  62. var Container = /** @class */ (function (_super) {
  63. tslib_1.__extends(Container, _super);
  64. function Container() {
  65. return _super !== null && _super.apply(this, arguments) || this;
  66. }
  67. Container.prototype.isCanvas = function () {
  68. return false;
  69. };
  70. // 根据子节点确定 BBox
  71. Container.prototype.getBBox = function () {
  72. // 所有的值可能在画布的可视区外
  73. var minX = Infinity;
  74. var maxX = -Infinity;
  75. var minY = Infinity;
  76. var maxY = -Infinity;
  77. // 将可见元素、图形以及不为空的图形分组筛选出来,用于包围盒合并
  78. var children = this.getChildren().filter(function (child) {
  79. return child.get('visible') && (!child.isGroup() || (child.isGroup() && child.getChildren().length > 0));
  80. });
  81. if (children.length > 0) {
  82. util_1.each(children, function (child) {
  83. var _a = child.getBBox(), childMinX = _a.minX, childMaxX = _a.maxX, childMinY = _a.minY, childMaxY = _a.maxY;
  84. if (childMinX < minX) {
  85. minX = childMinX;
  86. }
  87. if (childMaxX > maxX) {
  88. maxX = childMaxX;
  89. }
  90. if (childMinY < minY) {
  91. minY = childMinY;
  92. }
  93. if (childMaxY > maxY) {
  94. maxY = childMaxY;
  95. }
  96. });
  97. }
  98. else {
  99. minX = 0;
  100. maxX = 0;
  101. minY = 0;
  102. maxY = 0;
  103. }
  104. var box = {
  105. x: minX,
  106. y: minY,
  107. minX: minX,
  108. minY: minY,
  109. maxX: maxX,
  110. maxY: maxY,
  111. width: maxX - minX,
  112. height: maxY - minY,
  113. };
  114. return box;
  115. };
  116. // 获取画布的包围盒
  117. Container.prototype.getCanvasBBox = function () {
  118. var minX = Infinity;
  119. var maxX = -Infinity;
  120. var minY = Infinity;
  121. var maxY = -Infinity;
  122. // 将可见元素、图形以及不为空的图形分组筛选出来,用于包围盒合并
  123. var children = this.getChildren().filter(function (child) {
  124. return child.get('visible') && (!child.isGroup() || (child.isGroup() && child.getChildren().length > 0));
  125. });
  126. if (children.length > 0) {
  127. util_1.each(children, function (child) {
  128. var _a = child.getCanvasBBox(), childMinX = _a.minX, childMaxX = _a.maxX, childMinY = _a.minY, childMaxY = _a.maxY;
  129. if (childMinX < minX) {
  130. minX = childMinX;
  131. }
  132. if (childMaxX > maxX) {
  133. maxX = childMaxX;
  134. }
  135. if (childMinY < minY) {
  136. minY = childMinY;
  137. }
  138. if (childMaxY > maxY) {
  139. maxY = childMaxY;
  140. }
  141. });
  142. }
  143. else {
  144. minX = 0;
  145. maxX = 0;
  146. minY = 0;
  147. maxY = 0;
  148. }
  149. var box = {
  150. x: minX,
  151. y: minY,
  152. minX: minX,
  153. minY: minY,
  154. maxX: maxX,
  155. maxY: maxY,
  156. width: maxX - minX,
  157. height: maxY - minY,
  158. };
  159. return box;
  160. };
  161. Container.prototype.getDefaultCfg = function () {
  162. var cfg = _super.prototype.getDefaultCfg.call(this);
  163. cfg['children'] = [];
  164. return cfg;
  165. };
  166. Container.prototype.onAttrChange = function (name, value, originValue) {
  167. _super.prototype.onAttrChange.call(this, name, value, originValue);
  168. if (name === 'matrix') {
  169. var totalMatrix = this.getTotalMatrix();
  170. this._applyChildrenMarix(totalMatrix);
  171. }
  172. };
  173. // 不但应用到自己身上还要应用于子元素
  174. Container.prototype.applyMatrix = function (matrix) {
  175. var preTotalMatrix = this.getTotalMatrix();
  176. _super.prototype.applyMatrix.call(this, matrix);
  177. var totalMatrix = this.getTotalMatrix();
  178. // totalMatrix 没有发生变化时,这里仅考虑两者都为 null 时
  179. // 不继续向下传递矩阵
  180. if (totalMatrix === preTotalMatrix) {
  181. return;
  182. }
  183. this._applyChildrenMarix(totalMatrix);
  184. };
  185. // 在子元素上设置矩阵
  186. Container.prototype._applyChildrenMarix = function (totalMatrix) {
  187. var children = this.getChildren();
  188. util_1.each(children, function (child) {
  189. child.applyMatrix(totalMatrix);
  190. });
  191. };
  192. // 兼容老版本的接口
  193. Container.prototype.addShape = function () {
  194. var args = [];
  195. for (var _i = 0; _i < arguments.length; _i++) {
  196. args[_i] = arguments[_i];
  197. }
  198. var type = args[0];
  199. var cfg = args[1];
  200. if (util_1.isObject(type)) {
  201. cfg = type;
  202. }
  203. else {
  204. cfg['type'] = type;
  205. }
  206. var shapeType = SHAPE_MAP[cfg.type];
  207. if (!shapeType) {
  208. shapeType = util_1.upperFirst(cfg.type);
  209. SHAPE_MAP[cfg.type] = shapeType;
  210. }
  211. var ShapeBase = this.getShapeBase();
  212. var shape = new ShapeBase[shapeType](cfg);
  213. this.add(shape);
  214. return shape;
  215. };
  216. Container.prototype.addGroup = function () {
  217. var args = [];
  218. for (var _i = 0; _i < arguments.length; _i++) {
  219. args[_i] = arguments[_i];
  220. }
  221. var groupClass = args[0], cfg = args[1];
  222. var group;
  223. if (util_1.isFunction(groupClass)) {
  224. if (cfg) {
  225. group = new groupClass(cfg);
  226. }
  227. else {
  228. group = new groupClass({
  229. // canvas,
  230. parent: this,
  231. });
  232. }
  233. }
  234. else {
  235. var tmpCfg = groupClass || {};
  236. var TmpGroupClass = this.getGroupBase();
  237. group = new TmpGroupClass(tmpCfg);
  238. }
  239. this.add(group);
  240. return group;
  241. };
  242. Container.prototype.getCanvas = function () {
  243. var canvas;
  244. if (this.isCanvas()) {
  245. canvas = this;
  246. }
  247. else {
  248. canvas = this.get('canvas');
  249. }
  250. return canvas;
  251. };
  252. Container.prototype.getShape = function (x, y, ev) {
  253. // 如果不支持拾取,则直接返回
  254. if (!util_1.isAllowCapture(this)) {
  255. return null;
  256. }
  257. var children = this.getChildren();
  258. var shape;
  259. // 如果容器是 group
  260. if (!this.isCanvas()) {
  261. var v = [x, y, 1];
  262. // 将 x, y 转换成对应于 group 的局部坐标
  263. v = this.invertFromMatrix(v);
  264. if (!this.isClipped(v[0], v[1])) {
  265. shape = this._findShape(children, v[0], v[1], ev);
  266. }
  267. }
  268. else {
  269. shape = this._findShape(children, x, y, ev);
  270. }
  271. return shape;
  272. };
  273. Container.prototype._findShape = function (children, x, y, ev) {
  274. var shape = null;
  275. for (var i = children.length - 1; i >= 0; i--) {
  276. var child = children[i];
  277. if (util_1.isAllowCapture(child)) {
  278. if (child.isGroup()) {
  279. shape = child.getShape(x, y, ev);
  280. }
  281. else if (child.isHit(x, y)) {
  282. shape = child;
  283. }
  284. }
  285. if (shape) {
  286. break;
  287. }
  288. }
  289. return shape;
  290. };
  291. Container.prototype.add = function (element) {
  292. var canvas = this.getCanvas();
  293. var children = this.getChildren();
  294. var timeline = this.get('timeline');
  295. var preParent = element.getParent();
  296. if (preParent) {
  297. removeChild(preParent, element, false);
  298. }
  299. element.set('parent', this);
  300. if (canvas) {
  301. setCanvas(element, canvas);
  302. }
  303. if (timeline) {
  304. setTimeline(element, timeline);
  305. }
  306. children.push(element);
  307. element.onCanvasChange('add');
  308. this._applyElementMatrix(element);
  309. };
  310. // 将当前容器的矩阵应用到子元素
  311. Container.prototype._applyElementMatrix = function (element) {
  312. var totalMatrix = this.getTotalMatrix();
  313. // 添加图形或者分组时,需要把当前图元的矩阵设置进去
  314. if (totalMatrix) {
  315. element.applyMatrix(totalMatrix);
  316. }
  317. };
  318. Container.prototype.getChildren = function () {
  319. return this.get('children');
  320. };
  321. Container.prototype.sort = function () {
  322. var children = this.getChildren();
  323. // 稳定排序
  324. util_1.each(children, function (child, index) {
  325. child[INDEX] = index;
  326. return child;
  327. });
  328. children.sort(getComparer(function (obj1, obj2) {
  329. return obj1.get('zIndex') - obj2.get('zIndex');
  330. }));
  331. this.onCanvasChange('sort');
  332. };
  333. Container.prototype.clear = function () {
  334. this.set('clearing', true);
  335. if (this.destroyed) {
  336. return;
  337. }
  338. var children = this.getChildren();
  339. for (var i = children.length - 1; i >= 0; i--) {
  340. children[i].destroy(); // 销毁子元素
  341. }
  342. this.set('children', []);
  343. this.onCanvasChange('clear');
  344. this.set('clearing', false);
  345. };
  346. Container.prototype.destroy = function () {
  347. if (this.get('destroyed')) {
  348. return;
  349. }
  350. this.clear();
  351. _super.prototype.destroy.call(this);
  352. };
  353. /**
  354. * 获取第一个子元素
  355. * @return {IElement} 第一个元素
  356. */
  357. Container.prototype.getFirst = function () {
  358. return this.getChildByIndex(0);
  359. };
  360. /**
  361. * 获取最后一个子元素
  362. * @return {IElement} 元素
  363. */
  364. Container.prototype.getLast = function () {
  365. var children = this.getChildren();
  366. return this.getChildByIndex(children.length - 1);
  367. };
  368. /**
  369. * 根据索引获取子元素
  370. * @return {IElement} 第一个元素
  371. */
  372. Container.prototype.getChildByIndex = function (index) {
  373. var children = this.getChildren();
  374. return children[index];
  375. };
  376. /**
  377. * 子元素的数量
  378. * @return {number} 子元素数量
  379. */
  380. Container.prototype.getCount = function () {
  381. var children = this.getChildren();
  382. return children.length;
  383. };
  384. /**
  385. * 是否包含对应元素
  386. * @param {IElement} element 元素
  387. * @return {boolean}
  388. */
  389. Container.prototype.contain = function (element) {
  390. var children = this.getChildren();
  391. return children.indexOf(element) > -1;
  392. };
  393. /**
  394. * 移除对应子元素
  395. * @param {IElement} element 子元素
  396. * @param {boolean} destroy 是否销毁子元素,默认为 true
  397. */
  398. Container.prototype.removeChild = function (element, destroy) {
  399. if (destroy === void 0) { destroy = true; }
  400. if (this.contain(element)) {
  401. element.remove(destroy);
  402. }
  403. };
  404. /**
  405. * 查找所有匹配的元素
  406. * @param {ElementFilterFn} fn 匹配函数
  407. * @return {IElement[]} 元素数组
  408. */
  409. Container.prototype.findAll = function (fn) {
  410. var rst = [];
  411. var children = this.getChildren();
  412. util_1.each(children, function (element) {
  413. if (fn(element)) {
  414. rst.push(element);
  415. }
  416. if (element.isGroup()) {
  417. rst = rst.concat(element.findAll(fn));
  418. }
  419. });
  420. return rst;
  421. };
  422. /**
  423. * 查找元素,找到第一个返回
  424. * @param {ElementFilterFn} fn 匹配函数
  425. * @return {IElement|null} 元素,可以为空
  426. */
  427. Container.prototype.find = function (fn) {
  428. var rst = null;
  429. var children = this.getChildren();
  430. util_1.each(children, function (element) {
  431. if (fn(element)) {
  432. rst = element;
  433. }
  434. else if (element.isGroup()) {
  435. rst = element.find(fn);
  436. }
  437. if (rst) {
  438. return false;
  439. }
  440. });
  441. return rst;
  442. };
  443. /**
  444. * 根据 ID 查找元素
  445. * @param {string} id 元素 id
  446. * @return {IElement|null} 元素
  447. */
  448. Container.prototype.findById = function (id) {
  449. return this.find(function (element) {
  450. return element.get('id') === id;
  451. });
  452. };
  453. /**
  454. * 该方法即将废弃,不建议使用
  455. * 根据 className 查找元素
  456. * TODO: 该方式定义暂时只给 G6 3.3 以后的版本使用,待 G6 中的 findByClassName 方法移除后,G 也需要同步移除
  457. * @param {string} className 元素 className
  458. * @return {IElement | null} 元素
  459. */
  460. Container.prototype.findByClassName = function (className) {
  461. return this.find(function (element) {
  462. return element.get('className') === className;
  463. });
  464. };
  465. /**
  466. * 根据 name 查找元素列表
  467. * @param {string} name 元素名称
  468. * @return {IElement[]} 元素
  469. */
  470. Container.prototype.findAllByName = function (name) {
  471. return this.findAll(function (element) {
  472. return element.get('name') === name;
  473. });
  474. };
  475. return Container;
  476. }(element_1.default));
  477. exports.default = Container;
  478. //# sourceMappingURL=container.js.map