container.js 15 KB

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