category.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var tslib_1 = require("tslib");
  4. var util_1 = require("@antv/util");
  5. var label_1 = require("../util/label");
  6. var matrix_1 = require("../util/matrix");
  7. var state_1 = require("../util/state");
  8. var theme_1 = require("../util/theme");
  9. var base_1 = require("./base");
  10. /**
  11. * 分页器 默认配置
  12. */
  13. var DEFAULT_PAGE_NAVIGATOR = {
  14. marker: {
  15. style: {
  16. inactiveFill: '#000',
  17. inactiveOpacity: 0.45,
  18. fill: '#000',
  19. opacity: 1,
  20. size: 12,
  21. },
  22. },
  23. text: {
  24. style: {
  25. fill: '#ccc',
  26. fontSize: 12,
  27. },
  28. },
  29. };
  30. // 默认 文本style
  31. var textStyle = {
  32. fill: theme_1.default.textColor,
  33. fontSize: 12,
  34. textAlign: 'start',
  35. textBaseline: 'middle',
  36. fontFamily: theme_1.default.fontFamily,
  37. fontWeight: 'normal',
  38. lineHeight: 12,
  39. };
  40. var RIGHT_ARROW_NAME = 'navigation-arrow-right';
  41. var LEFT_ARROW_NAME = 'navigation-arrow-left';
  42. var ROTATE_MAP = {
  43. right: (90 * Math.PI) / 180,
  44. left: ((360 - 90) * Math.PI) / 180,
  45. up: 0,
  46. down: (180 * Math.PI) / 180,
  47. };
  48. var Category = /** @class */ (function (_super) {
  49. tslib_1.__extends(Category, _super);
  50. function Category() {
  51. var _this = _super !== null && _super.apply(this, arguments) || this;
  52. _this.currentPageIndex = 1;
  53. _this.totalPagesCnt = 1;
  54. _this.pageWidth = 0;
  55. _this.pageHeight = 0;
  56. _this.startX = 0;
  57. _this.startY = 0;
  58. _this.onNavigationBack = function () {
  59. var itemGroup = _this.getElementByLocalId('item-group');
  60. if (_this.currentPageIndex > 1) {
  61. _this.currentPageIndex -= 1;
  62. _this.updateNavigation();
  63. var matrix = _this.getCurrentNavigationMatrix();
  64. if (_this.get('animate')) {
  65. itemGroup.animate({
  66. matrix: matrix,
  67. }, 100);
  68. }
  69. else {
  70. itemGroup.attr({ matrix: matrix });
  71. }
  72. }
  73. };
  74. _this.onNavigationAfter = function () {
  75. var itemGroup = _this.getElementByLocalId('item-group');
  76. if (_this.currentPageIndex < _this.totalPagesCnt) {
  77. _this.currentPageIndex += 1;
  78. _this.updateNavigation();
  79. var matrix = _this.getCurrentNavigationMatrix();
  80. if (_this.get('animate')) {
  81. itemGroup.animate({
  82. matrix: matrix,
  83. }, 100);
  84. }
  85. else {
  86. itemGroup.attr({ matrix: matrix });
  87. }
  88. }
  89. };
  90. return _this;
  91. }
  92. Category.prototype.getDefaultCfg = function () {
  93. var cfg = _super.prototype.getDefaultCfg.call(this);
  94. return tslib_1.__assign(tslib_1.__assign({}, cfg), { name: 'legend', type: 'category', itemSpacing: 24, itemMarginBottom: 8, maxItemWidth: null, itemWidth: null, itemHeight: null, itemName: {}, itemValue: null, maxWidth: null, maxHeight: null, marker: {}, radio: null, items: [], itemStates: {}, itemBackground: {}, pageNavigator: {}, defaultCfg: {
  95. title: {
  96. spacing: 5,
  97. style: {
  98. fill: theme_1.default.textColor,
  99. fontSize: 12,
  100. textAlign: 'start',
  101. textBaseline: 'top',
  102. },
  103. },
  104. background: {
  105. padding: 5,
  106. style: {
  107. stroke: theme_1.default.lineColor,
  108. },
  109. },
  110. itemBackground: {
  111. style: {
  112. opacity: 0,
  113. fill: '#fff',
  114. },
  115. },
  116. pageNavigator: DEFAULT_PAGE_NAVIGATOR,
  117. itemName: {
  118. spacing: 16,
  119. style: textStyle,
  120. },
  121. marker: {
  122. spacing: 8,
  123. style: {
  124. r: 6,
  125. symbol: 'circle',
  126. },
  127. },
  128. itemValue: {
  129. alignRight: false,
  130. formatter: null,
  131. style: textStyle,
  132. spacing: 6,
  133. },
  134. itemStates: {
  135. active: {
  136. nameStyle: {
  137. opacity: 0.8,
  138. },
  139. },
  140. unchecked: {
  141. nameStyle: {
  142. fill: theme_1.default.uncheckedColor,
  143. },
  144. markerStyle: {
  145. fill: theme_1.default.uncheckedColor,
  146. stroke: theme_1.default.uncheckedColor,
  147. },
  148. },
  149. inactive: {
  150. nameStyle: {
  151. fill: theme_1.default.uncheckedColor,
  152. },
  153. markerStyle: {
  154. opacity: 0.2,
  155. },
  156. },
  157. },
  158. } });
  159. };
  160. // 实现 IList 接口
  161. Category.prototype.isList = function () {
  162. return true;
  163. };
  164. /**
  165. * 获取图例项
  166. * @return {ListItem[]} 列表项集合
  167. */
  168. Category.prototype.getItems = function () {
  169. return this.get('items');
  170. };
  171. /**
  172. * 设置列表项
  173. * @param {ListItem[]} items 列表项集合
  174. */
  175. Category.prototype.setItems = function (items) {
  176. this.update({
  177. items: items,
  178. });
  179. };
  180. /**
  181. * 更新列表项
  182. * @param {ListItem} item 列表项
  183. * @param {object} cfg 列表项
  184. */
  185. Category.prototype.updateItem = function (item, cfg) {
  186. util_1.mix(item, cfg);
  187. this.clear(); // 由于单个图例项变化,会引起全局变化,所以全部更新
  188. this.render();
  189. };
  190. /**
  191. * 清空列表
  192. */
  193. Category.prototype.clearItems = function () {
  194. var itemGroup = this.getElementByLocalId('item-group');
  195. itemGroup && itemGroup.clear();
  196. };
  197. /**
  198. * 设置列表项的状态
  199. * @param {ListItem} item 列表项
  200. * @param {string} state 状态名
  201. * @param {boolean} value 状态值, true, false
  202. */
  203. Category.prototype.setItemState = function (item, state, value) {
  204. item[state] = value;
  205. var itemElement = this.getElementByLocalId("item-" + item.id);
  206. if (itemElement) {
  207. var items = this.getItems();
  208. var index = items.indexOf(item);
  209. var offsetGroup = this.createOffScreenGroup(); // 离屏的 group
  210. var newElement = this.drawItem(item, index, this.getItemHeight(), offsetGroup);
  211. this.updateElements(newElement, itemElement); // 更新整个分组
  212. this.clearUpdateStatus(itemElement); // 清理更新状态,防止出现 bug
  213. }
  214. };
  215. /**
  216. * 是否存在指定的状态
  217. * @param {ListItem} item 列表项
  218. * @param {boolean} state 状态名
  219. */
  220. Category.prototype.hasState = function (item, state) {
  221. return !!item[state];
  222. };
  223. Category.prototype.getItemStates = function (item) {
  224. var itemStates = this.get('itemStates');
  225. var rst = [];
  226. util_1.each(itemStates, function (v, k) {
  227. if (item[k]) {
  228. // item.selected
  229. rst.push(k);
  230. }
  231. });
  232. return rst;
  233. };
  234. /**
  235. * 清楚所有列表项的状态
  236. * @param {string} state 状态值
  237. */
  238. Category.prototype.clearItemsState = function (state) {
  239. var _this = this;
  240. var items = this.getItemsByState(state);
  241. util_1.each(items, function (item) {
  242. _this.setItemState(item, state, false);
  243. });
  244. };
  245. /**
  246. * 根据状态获取图例项
  247. * @param {string} state [description]
  248. * @return {ListItem[]} [description]
  249. */
  250. Category.prototype.getItemsByState = function (state) {
  251. var _this = this;
  252. var items = this.getItems();
  253. return util_1.filter(items, function (item) {
  254. return _this.hasState(item, state);
  255. });
  256. };
  257. // 绘制 legend 的选项
  258. Category.prototype.drawLegendContent = function (group) {
  259. this.processItems();
  260. this.drawItems(group);
  261. };
  262. // 防止未设置 id
  263. Category.prototype.processItems = function () {
  264. var items = this.get('items');
  265. util_1.each(items, function (item) {
  266. if (!item.id) {
  267. // 如果没有设置 id,默认使用 name
  268. item.id = item.name;
  269. }
  270. });
  271. };
  272. // 绘制所有的图例选项
  273. Category.prototype.drawItems = function (group) {
  274. var _this = this;
  275. var itemContainerGroup = this.addGroup(group, {
  276. id: this.getElementId('item-container-group'),
  277. name: 'legend-item-container-group',
  278. });
  279. var itemGroup = this.addGroup(itemContainerGroup, {
  280. id: this.getElementId('item-group'),
  281. name: 'legend-item-group',
  282. });
  283. var itemHeight = this.getItemHeight();
  284. var itemWidth = this.get('itemWidth');
  285. var itemSpacing = this.get('itemSpacing');
  286. var itemMarginBottom = this.get('itemMarginBottom');
  287. var currentPoint = this.get('currentPoint');
  288. var startX = currentPoint.x;
  289. var startY = currentPoint.y;
  290. var layout = this.get('layout');
  291. var items = this.get('items');
  292. var wrapped = false;
  293. var pageWidth = 0;
  294. var maxWidth = this.get('maxWidth'); // 最大宽度,会导致 layout : 'horizontal' 时自动换行
  295. var maxHeight = this.get('maxHeight'); // 最大高度,会导致出现分页
  296. // 暂时不考虑分页
  297. util_1.each(items, function (item, index) {
  298. var subGroup = _this.drawItem(item, index, itemHeight, itemGroup);
  299. var bbox = subGroup.getBBox();
  300. var width = itemWidth || bbox.width;
  301. if (width > pageWidth) {
  302. pageWidth = width;
  303. }
  304. if (layout === 'horizontal') {
  305. // 如果水平布局
  306. if (maxWidth && maxWidth < currentPoint.x + width - startX) {
  307. // 检测是否换行
  308. wrapped = true;
  309. currentPoint.x = startX;
  310. currentPoint.y += itemHeight + itemMarginBottom;
  311. }
  312. _this.moveElementTo(subGroup, currentPoint);
  313. currentPoint.x += width + itemSpacing;
  314. }
  315. else {
  316. // 如果垂直布局
  317. if (maxHeight && maxHeight < currentPoint.y + itemHeight + itemMarginBottom - startY) {
  318. // 换行
  319. wrapped = true;
  320. currentPoint.x += pageWidth + itemSpacing;
  321. currentPoint.y = startY;
  322. pageWidth = 0;
  323. }
  324. _this.moveElementTo(subGroup, currentPoint);
  325. currentPoint.y += itemHeight + itemMarginBottom; // itemSpacing 仅影响水平间距
  326. }
  327. });
  328. if (wrapped && this.get('flipPage')) {
  329. this.pageHeight = 0;
  330. this.pageWidth = 0;
  331. this.totalPagesCnt = 1;
  332. this.startX = startX;
  333. this.startY = startY;
  334. this.adjustNavigation(group, itemGroup);
  335. }
  336. };
  337. // 获取图例项的高度,如果未定义,则按照 name 的高度计算
  338. Category.prototype.getItemHeight = function () {
  339. var itemHeight = this.get('itemHeight');
  340. if (!itemHeight) {
  341. var style_1 = (this.get('itemName') || {}).style;
  342. if (util_1.isFunction(style_1)) {
  343. var items_1 = this.getItems();
  344. items_1.forEach(function (item, index) {
  345. var fontSize = tslib_1.__assign(tslib_1.__assign({}, textStyle), style_1(item, index, items_1)).fontSize;
  346. if (itemHeight < fontSize) {
  347. itemHeight = fontSize;
  348. }
  349. });
  350. }
  351. else if (style_1) {
  352. itemHeight = style_1.fontSize;
  353. }
  354. }
  355. return itemHeight;
  356. };
  357. // 绘制 marker
  358. Category.prototype.drawMarker = function (container, markerCfg, item, itemHeight) {
  359. var markerAttrs = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({ x: 0, y: itemHeight / 2 }, markerCfg.style), { symbol: util_1.get(item.marker, 'symbol', 'circle') }), util_1.get(item.marker, 'style', {}));
  360. var shape = this.addShape(container, {
  361. type: 'marker',
  362. id: this.getElementId("item-" + item.id + "-marker"),
  363. name: 'legend-item-marker',
  364. attrs: markerAttrs,
  365. });
  366. var bbox = shape.getBBox();
  367. shape.attr('x', bbox.width / 2); // marker 需要左对齐,所以不能占用左侧的空间
  368. var _a = shape.attr(), stroke = _a.stroke, fill = _a.fill;
  369. if (stroke) {
  370. shape.set('isStroke', true);
  371. }
  372. if (fill) {
  373. shape.set('isFill', true);
  374. }
  375. return shape;
  376. };
  377. // 绘制文本
  378. Category.prototype.drawItemText = function (container, textName, cfg, item, itemHeight, xPosition, index) {
  379. var formatter = cfg.formatter;
  380. var style = cfg.style;
  381. var attrs = tslib_1.__assign(tslib_1.__assign({ x: xPosition, y: itemHeight / 2, text: formatter ? formatter(item[textName], item, index) : item[textName] }, textStyle), (util_1.isFunction(style) ? style(item, index, this.getItems()) : style));
  382. return this.addShape(container, {
  383. type: 'text',
  384. id: this.getElementId("item-" + item.id + "-" + textName),
  385. name: "legend-item-" + textName,
  386. attrs: attrs,
  387. });
  388. };
  389. Category.prototype.drawRadio = function (container, radioCfg, item, itemHeight, x) {
  390. var _a, _b;
  391. var style = radioCfg.style || {};
  392. // 以用户设置的 r 为主
  393. var r = (_a = style.r) !== null && _a !== void 0 ? _a : itemHeight / 2;
  394. var lineWidth = (r * 3.6) / 8;
  395. var _c = [x + r, itemHeight / 2 - r], x0 = _c[0], y0 = _c[1];
  396. var _d = [x0 + r, y0 + r], x1 = _d[0], y1 = _d[1];
  397. var _e = [x0, y1 + r], x2 = _e[0], y2 = _e[1];
  398. var _f = [x, y0 + r], x3 = _f[0], y3 = _f[1];
  399. var showRadio = item.showRadio;
  400. var attrs = tslib_1.__assign(tslib_1.__assign({ path: [
  401. ['M', x0, y0],
  402. ['A', r, r, 0, 0, 1, x1, y1],
  403. ['L', x1 - lineWidth, y1],
  404. ['L', x1, y1],
  405. ['A', r, r, 0, 0, 1, x2, y2],
  406. ['L', x2, y2 - lineWidth],
  407. ['L', x2, y2],
  408. ['A', r, r, 0, 0, 1, x3, y3],
  409. ['L', x3 + lineWidth, y3],
  410. ['L', x3, y3],
  411. ['A', r, r, 0, 0, 1, x0, y0],
  412. ['L', x0, y0 + lineWidth],
  413. ], stroke: '#000000', fill: '#ffffff' }, style), { opacity: showRadio ? ((_b = style === null || style === void 0 ? void 0 : style.opacity) !== null && _b !== void 0 ? _b : 0.45) : 0 });
  414. var radioShape = this.addShape(container, {
  415. type: 'path',
  416. id: this.getElementId("item-" + item.id + "-radio"),
  417. name: 'legend-item-radio',
  418. attrs: attrs,
  419. });
  420. radioShape.set('tip', radioCfg.tip);
  421. return radioShape;
  422. };
  423. // 绘制图例项
  424. Category.prototype.drawItem = function (item, index, itemHeight, itemGroup) {
  425. var groupId = "item-" + item.id;
  426. // 设置单独的 Group 用于 setClip
  427. var subContainer = this.addGroup(itemGroup, {
  428. name: 'legend-item-container',
  429. id: this.getElementId("item-container-" + groupId),
  430. delegateObject: {
  431. item: item,
  432. index: index,
  433. },
  434. });
  435. var subGroup = this.addGroup(subContainer, {
  436. name: 'legend-item',
  437. id: this.getElementId(groupId),
  438. delegateObject: {
  439. item: item,
  440. index: index,
  441. },
  442. });
  443. var marker = this.get('marker');
  444. var itemName = this.get('itemName');
  445. var itemValue = this.get('itemValue');
  446. var itemBackground = this.get('itemBackground');
  447. var radio = this.get('radio');
  448. var itemWidth = this.getLimitItemWidth();
  449. var curX = 0; // 记录当前 x 的位置
  450. if (marker) {
  451. var markerShape = this.drawMarker(subGroup, marker, item, itemHeight);
  452. var spacing = marker.spacing;
  453. var itemMarkerSpacing = util_1.get(item, ['marker', 'spacing']);
  454. if (util_1.isNumber(itemMarkerSpacing)) {
  455. // 如果 item 有配置 marker.spacing,采用 item 的配置
  456. spacing = itemMarkerSpacing;
  457. }
  458. curX = markerShape.getBBox().maxX + spacing;
  459. }
  460. if (itemName) {
  461. var nameShape = this.drawItemText(subGroup, 'name', itemName, item, itemHeight, curX, index);
  462. if (itemWidth) {
  463. // 设置了 item 的最大宽度限制,并且超出了,进行省略处理
  464. label_1.ellipsisLabel(true, nameShape, util_1.clamp(itemWidth - curX, 0, itemWidth));
  465. }
  466. curX = nameShape.getBBox().maxX + itemName.spacing;
  467. }
  468. if (itemValue) {
  469. var valueShape = this.drawItemText(subGroup, 'value', itemValue, item, itemHeight, curX, index);
  470. if (itemWidth) {
  471. if (itemValue.alignRight) {
  472. valueShape.attr({
  473. textAlign: 'right',
  474. x: itemWidth,
  475. });
  476. label_1.ellipsisLabel(true, valueShape, util_1.clamp(itemWidth - curX, 0, itemWidth), 'head');
  477. }
  478. else {
  479. label_1.ellipsisLabel(true, valueShape, util_1.clamp(itemWidth - curX, 0, itemWidth));
  480. }
  481. }
  482. curX = valueShape.getBBox().maxX + itemValue.spacing;
  483. }
  484. if (radio) {
  485. this.drawRadio(subGroup, radio, item, itemHeight, curX);
  486. }
  487. // 添加透明的背景,便于拾取和包围盒计算
  488. if (itemBackground) {
  489. var bbox = subGroup.getBBox();
  490. var backShape = this.addShape(subGroup, {
  491. type: 'rect',
  492. name: 'legend-item-background',
  493. id: this.getElementId(groupId + "-background"),
  494. attrs: tslib_1.__assign({ x: 0, y: 0, width: bbox.width, height: itemHeight }, itemBackground.style),
  495. });
  496. backShape.toBack();
  497. }
  498. this.applyItemStates(item, subGroup);
  499. return subGroup;
  500. };
  501. // 加上分页器并重新排序 items
  502. Category.prototype.adjustNavigation = function (container, itemGroup) {
  503. var _this = this;
  504. var startX = this.startX;
  505. var startY = this.startY;
  506. var layout = this.get('layout');
  507. var subGroups = itemGroup.findAll(function (item) { return item.get('name') === 'legend-item'; });
  508. var maxWidth = this.get('maxWidth');
  509. var maxHeight = this.get('maxHeight');
  510. var itemWidth = this.get('itemWidth');
  511. var itemSpacing = this.get('itemSpacing');
  512. var itemHeight = this.getItemHeight();
  513. var pageNavigator = util_1.deepMix({}, DEFAULT_PAGE_NAVIGATOR, this.get('pageNavigator'));
  514. var navigation = this.drawNavigation(container, layout, '00/00', pageNavigator);
  515. var navigationBBox = navigation.getBBox();
  516. var currentPoint = { x: startX, y: startY };
  517. var pages = 1;
  518. var widthLimit = 0;
  519. var pageWidth = 0;
  520. var maxItemWidth = 0;
  521. var itemMarginBottom = this.get('itemMarginBottom');
  522. /** 判断当前 item 是否溢出当前页。是的话,需要换行 */
  523. function shouldWrap(item, currentPoint) {
  524. var bbox = item.getBBox();
  525. var width = itemWidth || bbox.width;
  526. var newItemXPos = currentPoint.x + width + itemSpacing + navigationBBox.width;
  527. return newItemXPos > maxWidth;
  528. }
  529. if (layout === 'horizontal') {
  530. var maxRow = this.get('maxRow') || 1;
  531. var maxRowHeight_1 = itemHeight + (maxRow === 1 ? 0 : itemMarginBottom);
  532. // 分页器一直靠右上角
  533. var navigationX_1 = maxWidth - itemSpacing - navigationBBox.width - navigationBBox.minX; // 理论上不需要减 navigationBBox.minX
  534. this.pageHeight = maxRowHeight_1 * maxRow;
  535. this.pageWidth = navigationX_1;
  536. util_1.each(subGroups, function (item) {
  537. var bbox = item.getBBox();
  538. var width = itemWidth || bbox.width;
  539. if ((widthLimit && widthLimit < currentPoint.x + width + itemSpacing) ||
  540. shouldWrap(item, currentPoint)) {
  541. if (pages === 1) {
  542. widthLimit = currentPoint.x + itemSpacing;
  543. _this.moveElementTo(navigation, {
  544. x: navigationX_1,
  545. y: currentPoint.y + itemHeight / 2 - navigationBBox.height / 2 - navigationBBox.minY,
  546. });
  547. }
  548. pages += 1;
  549. currentPoint.x = startX;
  550. currentPoint.y += maxRowHeight_1;
  551. }
  552. _this.moveElementTo(item, currentPoint);
  553. item.getParent().setClip({
  554. type: 'rect',
  555. attrs: {
  556. x: currentPoint.x,
  557. y: currentPoint.y,
  558. width: width + itemSpacing,
  559. height: itemHeight,
  560. },
  561. });
  562. currentPoint.x += width + itemSpacing;
  563. });
  564. }
  565. else {
  566. util_1.each(subGroups, function (item) {
  567. var bbox = item.getBBox();
  568. if (bbox.width > pageWidth) {
  569. pageWidth = bbox.width;
  570. }
  571. });
  572. maxItemWidth = pageWidth;
  573. pageWidth += itemSpacing;
  574. if (maxWidth) {
  575. // maxWidth 限制加上
  576. pageWidth = Math.min(maxWidth, pageWidth);
  577. maxItemWidth = Math.min(maxWidth, maxItemWidth);
  578. }
  579. this.pageWidth = pageWidth;
  580. this.pageHeight = maxHeight - Math.max(navigationBBox.height, itemHeight + itemMarginBottom);
  581. var cntPerPage_1 = Math.floor(this.pageHeight / (itemHeight + itemMarginBottom));
  582. util_1.each(subGroups, function (item, index) {
  583. if (index !== 0 && index % cntPerPage_1 === 0) {
  584. pages += 1;
  585. currentPoint.x += pageWidth;
  586. currentPoint.y = startY;
  587. }
  588. _this.moveElementTo(item, currentPoint);
  589. item.getParent().setClip({
  590. type: 'rect',
  591. attrs: {
  592. x: currentPoint.x,
  593. y: currentPoint.y,
  594. width: pageWidth,
  595. height: itemHeight,
  596. },
  597. });
  598. currentPoint.y += itemHeight + itemMarginBottom;
  599. });
  600. this.totalPagesCnt = pages;
  601. this.moveElementTo(navigation, {
  602. x: startX + maxItemWidth / 2 - navigationBBox.width / 2 - navigationBBox.minX,
  603. y: maxHeight - navigationBBox.height - navigationBBox.minY,
  604. });
  605. }
  606. if (this.pageHeight && this.pageWidth) {
  607. // 为了使固定的 clip 生效,clip 设置在 itemContainerGroup 上,itemGroup 需要在翻页时会设置 matrix
  608. itemGroup.getParent().setClip({
  609. type: 'rect',
  610. attrs: {
  611. x: this.startX,
  612. y: this.startY,
  613. width: this.pageWidth,
  614. height: this.pageHeight,
  615. },
  616. });
  617. }
  618. // 重新计算 totalPagesCnt
  619. if (layout === 'horizontal' && this.get('maxRow')) {
  620. this.totalPagesCnt = Math.ceil(pages / this.get('maxRow'));
  621. }
  622. else {
  623. this.totalPagesCnt = pages;
  624. }
  625. if (this.currentPageIndex > this.totalPagesCnt) {
  626. this.currentPageIndex = 1;
  627. }
  628. this.updateNavigation(navigation);
  629. // update initial matrix
  630. itemGroup.attr('matrix', this.getCurrentNavigationMatrix());
  631. };
  632. /**
  633. * 绘制分页器
  634. */
  635. Category.prototype.drawNavigation = function (group, layout, text, styleCfg) {
  636. var currentPoint = { x: 0, y: 0 };
  637. var subGroup = this.addGroup(group, {
  638. id: this.getElementId('navigation-group'),
  639. name: 'legend-navigation',
  640. });
  641. var _a = util_1.get(styleCfg.marker, 'style', {}), _b = _a.size, size = _b === void 0 ? 12 : _b, arrowStyle = tslib_1.__rest(_a, ["size"]);
  642. var leftArrow = this.drawArrow(subGroup, currentPoint, LEFT_ARROW_NAME, layout === 'horizontal' ? 'up' : 'left', size, arrowStyle);
  643. leftArrow.on('click', this.onNavigationBack);
  644. var leftArrowBBox = leftArrow.getBBox();
  645. currentPoint.x += leftArrowBBox.width + 2;
  646. var textShape = this.addShape(subGroup, {
  647. type: 'text',
  648. id: this.getElementId('navigation-text'),
  649. name: 'navigation-text',
  650. attrs: tslib_1.__assign({ x: currentPoint.x, y: currentPoint.y + size / 2, text: text, textBaseline: 'middle' }, util_1.get(styleCfg.text, 'style')),
  651. });
  652. var textBBox = textShape.getBBox();
  653. currentPoint.x += textBBox.width + 2;
  654. var rightArrow = this.drawArrow(subGroup, currentPoint, RIGHT_ARROW_NAME, layout === 'horizontal' ? 'down' : 'right', size, arrowStyle);
  655. rightArrow.on('click', this.onNavigationAfter);
  656. return subGroup;
  657. };
  658. Category.prototype.updateNavigation = function (navigation) {
  659. var pageNavigator = util_1.deepMix({}, DEFAULT_PAGE_NAVIGATOR, this.get('pageNavigator'));
  660. var _a = pageNavigator.marker.style, fill = _a.fill, opacity = _a.opacity, inactiveFill = _a.inactiveFill, inactiveOpacity = _a.inactiveOpacity;
  661. var text = this.currentPageIndex + "/" + this.totalPagesCnt;
  662. var textShape = navigation ? navigation.getChildren()[1] : this.getElementByLocalId('navigation-text');
  663. var leftArrow = navigation
  664. ? navigation.findById(this.getElementId(LEFT_ARROW_NAME))
  665. : this.getElementByLocalId(LEFT_ARROW_NAME);
  666. var rightArrow = navigation
  667. ? navigation.findById(this.getElementId(RIGHT_ARROW_NAME))
  668. : this.getElementByLocalId(RIGHT_ARROW_NAME);
  669. textShape.attr('text', text);
  670. // 更新 left-arrow marker
  671. leftArrow.attr('opacity', this.currentPageIndex === 1 ? inactiveOpacity : opacity);
  672. leftArrow.attr('fill', this.currentPageIndex === 1 ? inactiveFill : fill);
  673. leftArrow.attr('cursor', this.currentPageIndex === 1 ? 'not-allowed' : 'pointer');
  674. // 更新 right-arrow marker
  675. rightArrow.attr('opacity', this.currentPageIndex === this.totalPagesCnt ? inactiveOpacity : opacity);
  676. rightArrow.attr('fill', this.currentPageIndex === this.totalPagesCnt ? inactiveFill : fill);
  677. rightArrow.attr('cursor', this.currentPageIndex === this.totalPagesCnt ? 'not-allowed' : 'pointer');
  678. // 更新位置
  679. var cursorX = leftArrow.getBBox().maxX + 2;
  680. textShape.attr('x', cursorX);
  681. cursorX += textShape.getBBox().width + 2;
  682. this.updateArrowPath(rightArrow, { x: cursorX, y: 0 });
  683. };
  684. Category.prototype.drawArrow = function (group, currentPoint, name, direction, size, style) {
  685. var x = currentPoint.x, y = currentPoint.y;
  686. var shape = this.addShape(group, {
  687. type: 'path',
  688. id: this.getElementId(name),
  689. name: name,
  690. attrs: tslib_1.__assign({ size: size,
  691. direction: direction, path: [['M', x + size / 2, y], ['L', x, y + size], ['L', x + size, y + size], ['Z']], cursor: 'pointer' }, style),
  692. });
  693. shape.attr('matrix', matrix_1.getMatrixByAngle({ x: x + size / 2, y: y + size / 2 }, ROTATE_MAP[direction]));
  694. return shape;
  695. };
  696. /**
  697. * 更新分页器 arrow 组件
  698. */
  699. Category.prototype.updateArrowPath = function (arrow, point) {
  700. var x = point.x, y = point.y;
  701. var _a = arrow.attr(), size = _a.size, direction = _a.direction;
  702. var matrix = matrix_1.getMatrixByAngle({ x: x + size / 2, y: y + size / 2 }, ROTATE_MAP[direction]);
  703. arrow.attr('path', [['M', x + size / 2, y], ['L', x, y + size], ['L', x + size, y + size], ['Z']]);
  704. arrow.attr('matrix', matrix);
  705. };
  706. Category.prototype.getCurrentNavigationMatrix = function () {
  707. var _a = this, currentPageIndex = _a.currentPageIndex, pageWidth = _a.pageWidth, pageHeight = _a.pageHeight;
  708. var layout = this.get('layout');
  709. var translate = layout === 'horizontal'
  710. ? {
  711. x: 0,
  712. y: pageHeight * (1 - currentPageIndex),
  713. }
  714. : {
  715. x: pageWidth * (1 - currentPageIndex),
  716. y: 0,
  717. };
  718. return matrix_1.getMatrixByTranslate(translate);
  719. };
  720. // 附加状态对应的样式
  721. Category.prototype.applyItemStates = function (item, subGroup) {
  722. var states = this.getItemStates(item);
  723. var hasStates = states.length > 0;
  724. if (hasStates) {
  725. var children = subGroup.getChildren();
  726. var itemStates_1 = this.get('itemStates');
  727. util_1.each(children, function (element) {
  728. var name = element.get('name');
  729. var elName = name.split('-')[2]; // marker, name, value
  730. var statesStyle = state_1.getStatesStyle(item, elName, itemStates_1);
  731. if (statesStyle) {
  732. element.attr(statesStyle);
  733. if (elName === 'marker' && !(element.get('isStroke') && element.get('isFill'))) {
  734. // 如果 marker 是单填充或者单描边的话,就不要额外添加 stroke 或这 fill 属性,否则会影响 unchecked 后的显示
  735. if (element.get('isStroke')) {
  736. element.attr('fill', null);
  737. }
  738. if (element.get('isFill')) {
  739. element.attr('stroke', null);
  740. }
  741. }
  742. }
  743. });
  744. }
  745. };
  746. // 获取 itemWidth 的最终设置
  747. Category.prototype.getLimitItemWidth = function () {
  748. var itemWidth = this.get('itemWidth');
  749. var maxItemWidth = this.get('maxItemWidth');
  750. if (maxItemWidth) {
  751. // 设置了最大宽度
  752. if (itemWidth) {
  753. maxItemWidth = itemWidth <= maxItemWidth ? itemWidth : maxItemWidth;
  754. }
  755. }
  756. else if (itemWidth) {
  757. maxItemWidth = itemWidth;
  758. }
  759. return maxItemWidth;
  760. };
  761. return Category;
  762. }(base_1.default));
  763. exports.default = Category;
  764. //# sourceMappingURL=category.js.map