drill-down.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import { __assign, __extends } from "tslib";
  2. import { Action, Util } from '@antv/g2';
  3. import { get, isNil, last, size } from '@antv/util';
  4. import { deepAssign } from '../../utils/deep-assign';
  5. // 面包屑文字和分割符'/'之间的距离
  6. var PADDING = 4;
  7. // 面包屑位置距离树图的距离
  8. var PADDING_LEFT = 0;
  9. // 面包屑位置距离树图的顶部距离
  10. export var PADDING_TOP = 5;
  11. /** Group name of breadCrumb: 面包屑 */
  12. export var BREAD_CRUMB_NAME = 'drilldown-bread-crumb';
  13. // 面包屑默认配置
  14. export var DEFAULT_BREAD_CRUMB_CONFIG = {
  15. /** 位置,默认:左上角 */
  16. position: 'top-left',
  17. dividerText: '/',
  18. textStyle: {
  19. fontSize: 12,
  20. fill: 'rgba(0, 0, 0, 0.65)',
  21. cursor: 'pointer',
  22. },
  23. activeTextStyle: {
  24. fill: '#87B5FF',
  25. },
  26. };
  27. /**
  28. * hierarchy 数据转换的参数
  29. */
  30. export var HIERARCHY_DATA_TRANSFORM_PARAMS = 'hierarchy-data-transform-params';
  31. /**
  32. * @description 下钻交互的 action
  33. * @author liuzhenying
  34. *
  35. * 适用于:hierarchy plot
  36. */
  37. var DrillDownAction = /** @class */ (function (_super) {
  38. __extends(DrillDownAction, _super);
  39. function DrillDownAction() {
  40. var _this = _super !== null && _super.apply(this, arguments) || this;
  41. /** Action name */
  42. _this.name = 'drill-down';
  43. // 存储历史下钻数据
  44. _this.historyCache = [];
  45. // 面包屑 group
  46. _this.breadCrumbGroup = null;
  47. // 面包屑基础配置
  48. _this.breadCrumbCfg = DEFAULT_BREAD_CRUMB_CONFIG;
  49. return _this;
  50. }
  51. /**
  52. * 点击事件, 下钻数据,并绘制面包屑
  53. */
  54. DrillDownAction.prototype.click = function () {
  55. var data = get(this.context, ['event', 'data', 'data']);
  56. if (!data)
  57. return false;
  58. this.drill(data);
  59. this.drawBreadCrumb();
  60. };
  61. /**
  62. * 重置位置,初始化及触发 chart afterchangesize 回调时使用
  63. */
  64. DrillDownAction.prototype.resetPosition = function () {
  65. // 当在第一层级未绘制面包屑,此时 changedata 触发 resetPosition 函数,需判断 this.breadCrumbGroup 是否存在
  66. if (!this.breadCrumbGroup)
  67. return;
  68. var coordinate = this.context.view.getCoordinate();
  69. var breadCrumbGroup = this.breadCrumbGroup;
  70. var bbox = breadCrumbGroup.getBBox();
  71. var position = this.getButtonCfg().position;
  72. // @todo 后续抽取一个函数来处理,以及增加 margin 或者 padding 的设置
  73. // 非 polar 的,需要使用 coordinate,除却图表组件
  74. var point = { x: coordinate.start.x, y: coordinate.end.y - (bbox.height + PADDING_TOP * 2) };
  75. if (coordinate.isPolar) {
  76. // 默认,左上角直接出发
  77. point = { x: 0, y: 0 };
  78. }
  79. if (position === 'bottom-left') {
  80. // 涉及到坐标反转的问题
  81. point = { x: coordinate.start.x, y: coordinate.start.y };
  82. }
  83. /** PADDING_LEFT, PADDING_TOP 与画布边缘的距离 */
  84. var matrix = Util.transform(null, [['t', point.x + PADDING_LEFT, point.y + bbox.height + PADDING_TOP]]);
  85. breadCrumbGroup.setMatrix(matrix);
  86. };
  87. /**
  88. * 返回上一层
  89. */
  90. DrillDownAction.prototype.back = function () {
  91. if (size(this.historyCache)) {
  92. this.backTo(this.historyCache.slice(0, -1));
  93. }
  94. };
  95. /**
  96. * 重置
  97. */
  98. DrillDownAction.prototype.reset = function () {
  99. if (this.historyCache[0]) {
  100. this.backTo(this.historyCache.slice(0, 1));
  101. }
  102. // 清空
  103. this.historyCache = [];
  104. this.hideCrumbGroup();
  105. };
  106. /**
  107. * 下钻数据并更新 view 显示层
  108. * @param nodeInfo 下钻数据
  109. */
  110. DrillDownAction.prototype.drill = function (nodeInfo) {
  111. var view = this.context.view;
  112. var transformData = get(view, ['interactions', 'drill-down', 'cfg', 'transformData'], function (v) { return v; });
  113. // 重新 update 数据
  114. var drillData = transformData(__assign({ data: nodeInfo.data }, nodeInfo[HIERARCHY_DATA_TRANSFORM_PARAMS]));
  115. view.changeData(drillData);
  116. // 存储历史记录
  117. var historyCache = [];
  118. var node = nodeInfo;
  119. while (node) {
  120. var nodeData = node.data;
  121. historyCache.unshift({
  122. id: "".concat(nodeData.name, "_").concat(node.height, "_").concat(node.depth),
  123. name: nodeData.name,
  124. // children 是实际数据
  125. children: transformData(__assign({ data: nodeData }, nodeInfo[HIERARCHY_DATA_TRANSFORM_PARAMS])),
  126. });
  127. node = node.parent;
  128. }
  129. this.historyCache = (this.historyCache || []).slice(0, -1).concat(historyCache);
  130. };
  131. /**
  132. * 回退事件,点击面包屑时触发
  133. * @param historyCache 当前要回退到的历史
  134. */
  135. DrillDownAction.prototype.backTo = function (historyCache) {
  136. if (!historyCache || historyCache.length <= 0) {
  137. return;
  138. }
  139. var view = this.context.view;
  140. var data = last(historyCache).children; // 处理后的数组
  141. view.changeData(data);
  142. if (historyCache.length > 1) {
  143. this.historyCache = historyCache;
  144. this.drawBreadCrumb();
  145. }
  146. else {
  147. // 清空
  148. this.historyCache = [];
  149. this.hideCrumbGroup();
  150. }
  151. };
  152. /**
  153. * 获取 mix 默认的配置和用户配置
  154. */
  155. DrillDownAction.prototype.getButtonCfg = function () {
  156. var view = this.context.view;
  157. var drillDownConfig = get(view, ['interactions', 'drill-down', 'cfg', 'drillDownConfig']);
  158. return deepAssign(this.breadCrumbCfg, drillDownConfig === null || drillDownConfig === void 0 ? void 0 : drillDownConfig.breadCrumb, this.cfg);
  159. };
  160. /**
  161. * 显示面包屑
  162. */
  163. DrillDownAction.prototype.drawBreadCrumb = function () {
  164. this.drawBreadCrumbGroup();
  165. this.resetPosition();
  166. this.breadCrumbGroup.show();
  167. };
  168. /**
  169. * 绘制 Button 和 文本
  170. */
  171. DrillDownAction.prototype.drawBreadCrumbGroup = function () {
  172. var _this = this;
  173. var config = this.getButtonCfg();
  174. var cache = this.historyCache;
  175. // 初始化面包屑 group
  176. if (!this.breadCrumbGroup) {
  177. this.breadCrumbGroup = this.context.view.foregroundGroup.addGroup({
  178. name: BREAD_CRUMB_NAME,
  179. });
  180. }
  181. else {
  182. this.breadCrumbGroup.clear();
  183. }
  184. // 绘制面包屑
  185. var left = 0;
  186. cache.forEach(function (record, index) {
  187. // 添加文本
  188. var textShape = _this.breadCrumbGroup.addShape({
  189. type: 'text',
  190. id: record.id,
  191. name: "".concat(BREAD_CRUMB_NAME, "_").concat(record.name, "_text"),
  192. attrs: __assign(__assign({ text: index === 0 && !isNil(config.rootText) ? config.rootText : record.name }, config.textStyle), { x: left, y: 0 }),
  193. });
  194. var textShapeBox = textShape.getBBox();
  195. left += textShapeBox.width + PADDING;
  196. // 增加文本事件
  197. textShape.on('click', function (event) {
  198. var _a;
  199. var targetId = event.target.get('id');
  200. if (targetId !== ((_a = last(cache)) === null || _a === void 0 ? void 0 : _a.id)) {
  201. var newHistoryCache = cache.slice(0, cache.findIndex(function (d) { return d.id === targetId; }) + 1);
  202. _this.backTo(newHistoryCache);
  203. }
  204. });
  205. // active 效果内置
  206. textShape.on('mouseenter', function (event) {
  207. var _a;
  208. var targetId = event.target.get('id');
  209. if (targetId !== ((_a = last(cache)) === null || _a === void 0 ? void 0 : _a.id)) {
  210. textShape.attr(config.activeTextStyle);
  211. }
  212. else {
  213. textShape.attr({ cursor: 'default' });
  214. }
  215. });
  216. textShape.on('mouseleave', function () {
  217. textShape.attr(config.textStyle);
  218. });
  219. if (index < cache.length - 1) {
  220. // 添加反斜杠
  221. var dividerShape = _this.breadCrumbGroup.addShape({
  222. type: 'text',
  223. name: "".concat(config.name, "_").concat(record.name, "_divider"),
  224. attrs: __assign(__assign({ text: config.dividerText }, config.textStyle), { x: left, y: 0 }),
  225. });
  226. var dividerBox = dividerShape.getBBox();
  227. left += dividerBox.width + PADDING;
  228. }
  229. });
  230. };
  231. /**
  232. * 隐藏面包屑
  233. */
  234. DrillDownAction.prototype.hideCrumbGroup = function () {
  235. if (this.breadCrumbGroup) {
  236. this.breadCrumbGroup.hide();
  237. }
  238. };
  239. /**
  240. * @override
  241. * destroy: 销毁资源
  242. */
  243. DrillDownAction.prototype.destroy = function () {
  244. if (this.breadCrumbGroup) {
  245. this.breadCrumbGroup.remove();
  246. }
  247. _super.prototype.destroy.call(this);
  248. };
  249. return DrillDownAction;
  250. }(Action));
  251. export { DrillDownAction };
  252. //# sourceMappingURL=drill-down.js.map