html.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import { __assign, __extends } from "tslib";
  2. import colorUtil from '@antv/color-util';
  3. import { createDom, modifyCSS } from '@antv/dom-util';
  4. import { each, hasKey, isElement, substitute } from '@antv/util';
  5. import HtmlComponent from '../abstract/html-component';
  6. import { clearDom, regionToBBox, toPx } from '../util/util';
  7. import * as CssConst from './css-const';
  8. import TooltipTheme from './html-theme';
  9. import { getAlignPoint } from '../util/align';
  10. function hasOneKey(obj, keys) {
  11. var result = false;
  12. each(keys, function (key) {
  13. if (hasKey(obj, key)) {
  14. result = true;
  15. return false;
  16. }
  17. });
  18. return result;
  19. }
  20. var Tooltip = /** @class */ (function (_super) {
  21. __extends(Tooltip, _super);
  22. function Tooltip() {
  23. return _super !== null && _super.apply(this, arguments) || this;
  24. }
  25. Tooltip.prototype.getDefaultCfg = function () {
  26. var cfg = _super.prototype.getDefaultCfg.call(this);
  27. return __assign(__assign({}, cfg), { name: 'tooltip', type: 'html', x: 0, y: 0, items: [], customContent: null, containerTpl: "<div class=\"" + CssConst.CONTAINER_CLASS + "\"><div class=\"" + CssConst.TITLE_CLASS + "\"></div><ul class=\"" + CssConst.LIST_CLASS + "\"></ul></div>", itemTpl: "<li class=\"" + CssConst.LIST_ITEM_CLASS + "\" data-index={index}>\n <span class=\"" + CssConst.MARKER_CLASS + "\" style=\"background:{color}\"></span>\n <span class=\"" + CssConst.NAME_CLASS + "\">{name}</span>:\n <span class=\"" + CssConst.VALUE_CLASS + "\">{value}</span>\n </li>", xCrosshairTpl: "<div class=\"" + CssConst.CROSSHAIR_X + "\"></div>", yCrosshairTpl: "<div class=\"" + CssConst.CROSSHAIR_Y + "\"></div>", title: null, showTitle: true,
  28. /**
  29. * tooltip 限制的区域
  30. * @type {Region}
  31. */
  32. region: null,
  33. // crosshair 的限制区域
  34. crosshairsRegion: null, containerClassName: CssConst.CONTAINER_CLASS,
  35. // x, y, xy
  36. crosshairs: null, offset: 10, position: 'right', domStyles: null, defaultStyles: TooltipTheme });
  37. };
  38. // tooltip 渲染时,渲染 title,items 和 corosshairs
  39. Tooltip.prototype.render = function () {
  40. if (this.get('customContent')) {
  41. this.renderCustomContent();
  42. }
  43. else {
  44. this.resetTitle();
  45. this.renderItems();
  46. }
  47. // 绘制完成后,再定位
  48. this.resetPosition();
  49. };
  50. // 复写清空函数,因为有模板的存在,所以默认的写法不合适
  51. Tooltip.prototype.clear = function () {
  52. // 由于 crosshair 没有在 container 内,所以需要单独清理
  53. this.clearCrosshairs();
  54. this.setTitle(''); // 清空标题
  55. this.clearItemDoms();
  56. };
  57. Tooltip.prototype.show = function () {
  58. var container = this.getContainer();
  59. if (!container || this.destroyed) {
  60. // 防止容器不存在或者被销毁时报错
  61. return;
  62. }
  63. this.set('visible', true);
  64. modifyCSS(container, {
  65. visibility: 'visible',
  66. });
  67. this.setCrossHairsVisible(true);
  68. };
  69. Tooltip.prototype.hide = function () {
  70. var container = this.getContainer();
  71. // relative: https://github.com/antvis/g2/issues/1221
  72. if (!container || this.destroyed) {
  73. return;
  74. }
  75. this.set('visible', false);
  76. modifyCSS(container, {
  77. visibility: 'hidden',
  78. });
  79. this.setCrossHairsVisible(false);
  80. };
  81. // 实现 IPointLocation 的接口
  82. Tooltip.prototype.getLocation = function () {
  83. return { x: this.get('x'), y: this.get('y') };
  84. };
  85. // 实现 IPointLocation 的接口
  86. Tooltip.prototype.setLocation = function (point) {
  87. this.set('x', point.x);
  88. this.set('y', point.y);
  89. this.resetPosition();
  90. };
  91. Tooltip.prototype.setCrossHairsVisible = function (visible) {
  92. var display = visible ? '' : 'none';
  93. var xCrosshairDom = this.get('xCrosshairDom');
  94. var yCrosshairDom = this.get('yCrosshairDom');
  95. xCrosshairDom &&
  96. modifyCSS(xCrosshairDom, {
  97. display: display,
  98. });
  99. yCrosshairDom &&
  100. modifyCSS(yCrosshairDom, {
  101. display: display,
  102. });
  103. };
  104. // 如有 customContent 则根据 customContent 设置 container
  105. Tooltip.prototype.initContainer = function () {
  106. _super.prototype.initContainer.call(this);
  107. if (this.get('customContent')) {
  108. if (this.get('container')) {
  109. this.get('container').remove();
  110. }
  111. var container = this.getHtmlContentNode();
  112. this.get('parent').appendChild(container);
  113. this.set('container', container);
  114. this.resetStyles();
  115. this.applyStyles();
  116. }
  117. };
  118. // 更新属性的同时,可能会引起 DOM 的变化,这里对可能引起 DOM 变化的场景做了处理
  119. Tooltip.prototype.updateInner = function (cfg) {
  120. if (this.get('customContent')) {
  121. this.renderCustomContent();
  122. }
  123. else {
  124. // 更新标题
  125. if (hasOneKey(cfg, ['title', 'showTitle'])) {
  126. this.resetTitle();
  127. }
  128. // 更新内容
  129. if (hasKey(cfg, 'items')) {
  130. this.renderItems();
  131. }
  132. }
  133. _super.prototype.updateInner.call(this, cfg);
  134. };
  135. Tooltip.prototype.initDom = function () {
  136. this.cacheDoms();
  137. };
  138. // 清理 DOM
  139. Tooltip.prototype.removeDom = function () {
  140. _super.prototype.removeDom.call(this);
  141. this.clearCrosshairs();
  142. };
  143. // 调整位置
  144. Tooltip.prototype.resetPosition = function () {
  145. var x = this.get('x');
  146. var y = this.get('y');
  147. var offset = this.get('offset');
  148. var _a = this.getOffset(), offsetX = _a.offsetX, offsetY = _a.offsetY;
  149. var position = this.get('position');
  150. var region = this.get('region');
  151. var container = this.getContainer();
  152. var bbox = this.getBBox();
  153. var width = bbox.width, height = bbox.height;
  154. var limitBox;
  155. if (region) {
  156. // 不限制位置
  157. limitBox = regionToBBox(region);
  158. }
  159. var point = getAlignPoint(x, y, offset, width, height, position, limitBox);
  160. modifyCSS(container, {
  161. left: toPx(point.x + offsetX),
  162. top: toPx(point.y + offsetY),
  163. });
  164. this.resetCrosshairs();
  165. };
  166. // 根据 customContent 渲染
  167. Tooltip.prototype.renderCustomContent = function () {
  168. var node = this.getHtmlContentNode();
  169. var parent = this.get('parent');
  170. var curContainer = this.get('container');
  171. if (curContainer && curContainer.parentNode === parent) {
  172. parent.replaceChild(node, curContainer);
  173. }
  174. else {
  175. parent.appendChild(node);
  176. }
  177. this.set('container', node);
  178. this.resetStyles();
  179. this.applyStyles();
  180. };
  181. Tooltip.prototype.getHtmlContentNode = function () {
  182. var node;
  183. var customContent = this.get('customContent');
  184. if (customContent) {
  185. var elem = customContent(this.get('title'), this.get('items'));
  186. if (isElement(elem)) {
  187. node = elem;
  188. }
  189. else {
  190. node = createDom(elem);
  191. }
  192. }
  193. return node;
  194. };
  195. // 缓存模板设置的各种 DOM
  196. Tooltip.prototype.cacheDoms = function () {
  197. var container = this.getContainer();
  198. var titleDom = container.getElementsByClassName(CssConst.TITLE_CLASS)[0];
  199. var listDom = container.getElementsByClassName(CssConst.LIST_CLASS)[0];
  200. this.set('titleDom', titleDom);
  201. this.set('listDom', listDom);
  202. };
  203. // 重置 title
  204. Tooltip.prototype.resetTitle = function () {
  205. var title = this.get('title');
  206. var showTitle = this.get('showTitle');
  207. if (showTitle && title) {
  208. this.setTitle(title);
  209. }
  210. else {
  211. this.setTitle('');
  212. }
  213. };
  214. // 设置 title 文本
  215. Tooltip.prototype.setTitle = function (text) {
  216. var titleDom = this.get('titleDom');
  217. if (titleDom) {
  218. titleDom.innerText = text;
  219. }
  220. };
  221. // 终止 crosshair
  222. Tooltip.prototype.resetCrosshairs = function () {
  223. var crosshairsRegion = this.get('crosshairsRegion');
  224. var crosshairs = this.get('crosshairs');
  225. if (!crosshairsRegion || !crosshairs) {
  226. // 不显示 crosshair,都移除,没有设定 region 也都移除掉
  227. this.clearCrosshairs();
  228. }
  229. else {
  230. var crosshairBox = regionToBBox(crosshairsRegion);
  231. var xCrosshairDom = this.get('xCrosshairDom');
  232. var yCrosshairDom = this.get('yCrosshairDom');
  233. if (crosshairs === 'x') {
  234. this.resetCrosshair('x', crosshairBox);
  235. // 仅显示 x 的 crosshair,y 移除
  236. if (yCrosshairDom) {
  237. yCrosshairDom.remove();
  238. this.set('yCrosshairDom', null);
  239. }
  240. }
  241. else if (crosshairs === 'y') {
  242. this.resetCrosshair('y', crosshairBox);
  243. // 仅显示 y 的 crosshair,x 移除
  244. if (xCrosshairDom) {
  245. xCrosshairDom.remove();
  246. this.set('xCrosshairDom', null);
  247. }
  248. }
  249. else {
  250. this.resetCrosshair('x', crosshairBox);
  251. this.resetCrosshair('y', crosshairBox);
  252. }
  253. this.setCrossHairsVisible(this.get('visible'));
  254. }
  255. };
  256. // 设定 crosshair 的位置,需要区分 x,y
  257. Tooltip.prototype.resetCrosshair = function (name, bbox) {
  258. var croshairDom = this.checkCrosshair(name);
  259. var value = this.get(name);
  260. if (name === 'x') {
  261. modifyCSS(croshairDom, {
  262. left: toPx(value),
  263. top: toPx(bbox.y),
  264. height: toPx(bbox.height),
  265. });
  266. }
  267. else {
  268. modifyCSS(croshairDom, {
  269. top: toPx(value),
  270. left: toPx(bbox.x),
  271. width: toPx(bbox.width),
  272. });
  273. }
  274. };
  275. // 如果 crosshair 对应的 dom 不存在,则创建
  276. Tooltip.prototype.checkCrosshair = function (name) {
  277. var domName = name + "CrosshairDom";
  278. var tplName = name + "CrosshairTpl";
  279. var constName = "CROSSHAIR_" + name.toUpperCase();
  280. var styleName = CssConst[constName];
  281. var croshairDom = this.get(domName);
  282. var parent = this.get('parent');
  283. if (!croshairDom) {
  284. croshairDom = createDom(this.get(tplName)); // 创建
  285. this.applyStyle(styleName, croshairDom); // 设置初始样式
  286. parent.appendChild(croshairDom); // 添加到跟 tooltip 同级的目录下
  287. this.set(domName, croshairDom);
  288. }
  289. return croshairDom;
  290. };
  291. Tooltip.prototype.renderItems = function () {
  292. this.clearItemDoms();
  293. var items = this.get('items');
  294. var itemTpl = this.get('itemTpl');
  295. var listDom = this.get('listDom');
  296. if (listDom) {
  297. each(items, function (item) {
  298. var color = colorUtil.toCSSGradient(item.color);
  299. var substituteObj = __assign(__assign({}, item), { color: color });
  300. var domStr = substitute(itemTpl, substituteObj);
  301. var itemDom = createDom(domStr);
  302. listDom.appendChild(itemDom);
  303. });
  304. this.applyChildrenStyles(listDom, this.get('domStyles'));
  305. }
  306. };
  307. Tooltip.prototype.clearItemDoms = function () {
  308. if (this.get('listDom')) {
  309. clearDom(this.get('listDom'));
  310. }
  311. };
  312. Tooltip.prototype.clearCrosshairs = function () {
  313. var xCrosshairDom = this.get('xCrosshairDom');
  314. var yCrosshairDom = this.get('yCrosshairDom');
  315. xCrosshairDom && xCrosshairDom.remove();
  316. yCrosshairDom && yCrosshairDom.remove();
  317. this.set('xCrosshairDom', null);
  318. this.set('yCrosshairDom', null);
  319. };
  320. return Tooltip;
  321. }(HtmlComponent));
  322. export default Tooltip;
  323. //# sourceMappingURL=html.js.map