import { __assign, __extends, __values } from "tslib"; import { deepMix, find, get, isEqual, isFunction, mix, isString, isBoolean, flatten, isArray } from '@antv/util'; import { Crosshair, HtmlTooltip } from '../../dependents'; import { getAngleByPoint, getDistanceToCenter, getCoordinateClipCfg } from '../../util/coordinate'; import { polarToCartesian } from '../../util/graphics'; import { findItemsFromView } from '../../util/tooltip'; import { BBox } from '../../util/bbox'; import { Controller } from './base'; import Event from '../event'; // Filter duplicates, use `name`, `color`, `value` and `title` property values as condition function uniq(items) { var uniqItems = []; var _loop_1 = function (index) { var item = items[index]; var result = find(uniqItems, function (subItem) { return (subItem.color === item.color && subItem.name === item.name && subItem.value === item.value && subItem.title === item.title); }); if (!result) { uniqItems.push(item); } }; for (var index = 0; index < items.length; index++) { _loop_1(index); } return uniqItems; } /** @ignore */ var Tooltip = /** @class */ (function (_super) { __extends(Tooltip, _super); function Tooltip() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.isLocked = false; return _this; } Object.defineProperty(Tooltip.prototype, "name", { get: function () { return 'tooltip'; }, enumerable: false, configurable: true }); Tooltip.prototype.init = function () { }; Tooltip.prototype.isVisible = function () { var option = this.view.getOptions().tooltip; return option !== false; }; Tooltip.prototype.render = function () { }; /** * Shows tooltip * @param point */ Tooltip.prototype.showTooltip = function (point) { this.point = point; if (!this.isVisible()) { // 如果设置 tooltip(false) 则始终不显示 return; } var view = this.view; var items = this.getTooltipItems(point); if (!items.length) { // 无内容则不展示,同时 tooltip 需要隐藏 this.hideTooltip(); return; } var title = this.getTitle(items); var dataPoint = { x: items[0].x, y: items[0].y, }; // 数据点位置 view.emit('tooltip:show', Event.fromData(view, 'tooltip:show', __assign({ items: items, title: title }, point))); var cfg = this.getTooltipCfg(); var follow = cfg.follow, showMarkers = cfg.showMarkers, showCrosshairs = cfg.showCrosshairs, showContent = cfg.showContent, marker = cfg.marker; var lastItems = this.items; var lastTitle = this.title; if (!isEqual(lastTitle, title) || !isEqual(lastItems, items)) { // 内容发生变化了更新 tooltip view.emit('tooltip:change', Event.fromData(view, 'tooltip:change', __assign({ items: items, title: title }, point))); if (isFunction(showContent) ? showContent(items) : showContent) { // 展示 tooltip 内容框才渲染 tooltip if (!this.tooltip) { // 延迟生成 this.renderTooltip(); } this.tooltip.update(mix({}, cfg, { items: this.getItemsAfterProcess(items), title: title, }, follow ? point : {})); this.tooltip.show(); } if (showMarkers) { // 展示 tooltipMarkers,tooltipMarkers 跟随数据 this.renderTooltipMarkers(items, marker); } } else { // 内容未发生变化,则更新位置 if (this.tooltip && follow) { this.tooltip.update(point); this.tooltip.show(); // tooltip 有可能被隐藏,需要保证显示状态 } if (this.tooltipMarkersGroup) { this.tooltipMarkersGroup.show(); } } this.items = items; this.title = title; if (showCrosshairs) { // 展示 tooltip 辅助线 var isCrosshairsFollowCursor = get(cfg, ['crosshairs', 'follow'], false); // 辅助线是否要跟随鼠标 this.renderCrosshairs(isCrosshairsFollowCursor ? point : dataPoint, cfg); } }; Tooltip.prototype.hideTooltip = function () { var follow = this.getTooltipCfg().follow; if (!follow) { this.point = null; return; } // hide the tooltipMarkers var tooltipMarkersGroup = this.tooltipMarkersGroup; if (tooltipMarkersGroup) { tooltipMarkersGroup.hide(); } // hide crosshairs var xCrosshair = this.xCrosshair; var yCrosshair = this.yCrosshair; if (xCrosshair) { xCrosshair.hide(); } if (yCrosshair) { yCrosshair.hide(); } var tooltip = this.tooltip; if (tooltip) { tooltip.hide(); } this.view.emit('tooltip:hide', Event.fromData(this.view, 'tooltip:hide', {})); this.point = null; }; /** * lockTooltip */ Tooltip.prototype.lockTooltip = function () { this.isLocked = true; if (this.tooltip) { // tooltip contianer 可捕获事件 this.tooltip.setCapture(true); } }; /** * unlockTooltip */ Tooltip.prototype.unlockTooltip = function () { this.isLocked = false; var cfg = this.getTooltipCfg(); if (this.tooltip) { // 重置 capture 属性 this.tooltip.setCapture(cfg.capture); } }; /** * isTooltipLocked */ Tooltip.prototype.isTooltipLocked = function () { return this.isLocked; }; Tooltip.prototype.clear = function () { var _a = this, tooltip = _a.tooltip, xCrosshair = _a.xCrosshair, yCrosshair = _a.yCrosshair, tooltipMarkersGroup = _a.tooltipMarkersGroup; if (tooltip) { tooltip.hide(); tooltip.clear(); } if (xCrosshair) { xCrosshair.clear(); } if (yCrosshair) { yCrosshair.clear(); } if (tooltipMarkersGroup) { tooltipMarkersGroup.clear(); } // 如果 customContent 不为空,就重新生成 tooltip if (tooltip === null || tooltip === void 0 ? void 0 : tooltip.get('customContent')) { this.tooltip.destroy(); this.tooltip = null; } // title 和 items 需要清空, 否则 tooltip 内容会出现置空的情况 // 即:需要走进 !isEqual(lastTitle, title) || !isEqual(lastItems, items) 的逻辑,更新 tooltip 的内容 this.title = null; this.items = null; }; Tooltip.prototype.destroy = function () { if (this.tooltip) { this.tooltip.destroy(); } if (this.xCrosshair) { this.xCrosshair.destroy(); } if (this.yCrosshair) { this.yCrosshair.destroy(); } if (this.guideGroup) { this.guideGroup.remove(true); } this.reset(); }; Tooltip.prototype.reset = function () { this.items = null; this.title = null; this.tooltipMarkersGroup = null; this.tooltipCrosshairsGroup = null; this.xCrosshair = null; this.yCrosshair = null; this.tooltip = null; this.guideGroup = null; this.isLocked = false; this.point = null; }; Tooltip.prototype.changeVisible = function (visible) { if (this.visible === visible) { return; } var _a = this, tooltip = _a.tooltip, tooltipMarkersGroup = _a.tooltipMarkersGroup, xCrosshair = _a.xCrosshair, yCrosshair = _a.yCrosshair; if (visible) { if (tooltip) { tooltip.show(); } if (tooltipMarkersGroup) { tooltipMarkersGroup.show(); } if (xCrosshair) { xCrosshair.show(); } if (yCrosshair) { yCrosshair.show(); } } else { if (tooltip) { tooltip.hide(); } if (tooltipMarkersGroup) { tooltipMarkersGroup.hide(); } if (xCrosshair) { xCrosshair.hide(); } if (yCrosshair) { yCrosshair.hide(); } } this.visible = visible; }; Tooltip.prototype.getTooltipItems = function (point) { var e_1, _a, e_2, _b, e_3, _c; var items = this.findItemsFromView(this.view, point); if (items.length) { // 三层 items = flatten(items); try { for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) { var itemArr = items_1_1.value; try { for (var itemArr_1 = (e_2 = void 0, __values(itemArr)), itemArr_1_1 = itemArr_1.next(); !itemArr_1_1.done; itemArr_1_1 = itemArr_1.next()) { var item = itemArr_1_1.value; var _d = item.mappingData, x = _d.x, y = _d.y; item.x = isArray(x) ? x[x.length - 1] : x; item.y = isArray(y) ? y[y.length - 1] : y; } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (itemArr_1_1 && !itemArr_1_1.done && (_b = itemArr_1.return)) _b.call(itemArr_1); } finally { if (e_2) throw e_2.error; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1); } finally { if (e_1) throw e_1.error; } } var shared = this.getTooltipCfg().shared; // shared: false 代表只显示当前拾取到的 shape 的数据,但是一个 view 会有多个 Geometry,所以有可能会拾取到多个 shape if (shared === false && items.length > 1) { var snapItem = items[0]; var min = Math.abs(point.y - snapItem[0].y); try { for (var items_2 = __values(items), items_2_1 = items_2.next(); !items_2_1.done; items_2_1 = items_2.next()) { var aItem = items_2_1.value; var yDistance = Math.abs(point.y - aItem[0].y); if (yDistance <= min) { snapItem = aItem; min = yDistance; } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (items_2_1 && !items_2_1.done && (_c = items_2.return)) _c.call(items_2); } finally { if (e_3) throw e_3.error; } } items = [snapItem]; } return uniq(flatten(items)); } return []; }; Tooltip.prototype.layout = function () { }; Tooltip.prototype.update = function () { if (this.point) { this.showTooltip(this.point); } if (this.tooltip) { // #2279 修复resize之后tooltip越界的问题 // 确保tooltip已经创建的情况下 var canvas = this.view.getCanvas(); // TODO 逍为 tooltip 的区域不应该是 canvas,而应该是整个 特别是在图比较小的时候 // 更新 region this.tooltip.set('region', { start: { x: 0, y: 0 }, end: { x: canvas.get('width'), y: canvas.get('height') }, }); } }; /** * 当前鼠标点是在 enter tooltip 中 * @param point */ Tooltip.prototype.isCursorEntered = function (point) { // 是可捕获的,并且点在 tooltip dom 上 if (this.tooltip) { var el = this.tooltip.getContainer(); var capture = this.tooltip.get('capture'); if (el && capture) { var _a = el.getBoundingClientRect(), x = _a.x, y = _a.y, width = _a.width, height = _a.height; return new BBox(x, y, width, height).isPointIn(point); } } return false; }; // 获取 tooltip 配置,因为用户可能会通过 view.tooltip() 重新配置 tooltip,所以就不做缓存,每次直接读取 Tooltip.prototype.getTooltipCfg = function () { var view = this.view; var option = view.getOptions().tooltip; var processOption = this.processCustomContent(option); var theme = view.getTheme(); var defaultCfg = get(theme, ['components', 'tooltip'], {}); var enterable = get(processOption, 'enterable', defaultCfg.enterable); return deepMix({}, defaultCfg, processOption, { capture: enterable || this.isLocked ? true : false, }); }; // process customContent Tooltip.prototype.processCustomContent = function (option) { if (isBoolean(option) || !get(option, 'customContent')) { return option; } var currentCustomContent = option.customContent; var customContent = function (title, items) { var content = currentCustomContent(title, items) || ''; return isString(content) ? '