NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/esm/chart/controller/tooltip.js

634 lines
23 KiB
Java
Raw Normal View History

2023-09-14 14:47:11 +08:00
import { __assign, __extends } from "tslib";
import { deepMix, find, flatten, get, isArray, isEqual, isFunction, isUndefined, mix } from '@antv/util';
import { Crosshair, HtmlTooltip } from '../../dependents';
import { getAngleByPoint, getDistanceToCenter, isPointInCoordinate } from '../../util/coordinate';
import { polarToCartesian } from '../../util/graphics';
import { findDataByPoint, getTooltipItems } from '../../util/tooltip';
import { Controller } from './base';
// 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;
_this.isVisible = true;
return _this;
}
Object.defineProperty(Tooltip.prototype, "name", {
get: function () {
return 'tooltip';
},
enumerable: false,
configurable: true
});
Tooltip.prototype.init = function () { };
Tooltip.prototype.render = function () {
var option = this.view.getOptions().tooltip;
this.isVisible = option !== false;
};
/**
* 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', __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', __assign({ items: items,
title: title }, point));
if (showContent) {
// 展示 tooltip 内容框才渲染 tooltip
if (!this.tooltip) {
// 延迟生成
this.renderTooltip();
}
this.tooltip.update(mix({}, cfg, {
items: items,
title: title,
}, follow ? point : {}));
this.tooltip.show();
}
if (showMarkers) {
// 展示 tooltipMarkerstooltipMarkers 跟随数据
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', {});
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();
}
};
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.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 items = this.findItemsFromView(this.view, point);
if (items.length) {
// 三层
items = flatten(items);
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var itemArr = items_1[_i];
for (var _a = 0, itemArr_1 = itemArr; _a < itemArr_1.length; _a++) {
var item = itemArr_1[_a];
var _b = item.mappingData, x = _b.x, y = _b.y;
item.x = isArray(x) ? x[x.length - 1] : x;
item.y = isArray(y) ? y[y.length - 1] : y;
}
}
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);
for (var _c = 0, items_2 = items; _c < items_2.length; _c++) {
var aItem = items_2[_c];
var yDistance = Math.abs(point.y - aItem[0].y);
if (yDistance <= min) {
snapItem = aItem;
min = yDistance;
}
}
items = [snapItem];
}
return uniq(flatten(items));
}
return [];
};
Tooltip.prototype.layout = function () { };
Tooltip.prototype.update = function () {
if (this.point) {
this.showTooltip(this.point);
}
};
// 获取 tooltip 配置,因为用户可能会通过 view.tooltip() 重新配置 tooltip所以就不做缓存每次直接读取
Tooltip.prototype.getTooltipCfg = function () {
var view = this.view;
var option = view.getOptions().tooltip;
var theme = view.getTheme();
var defaultCfg = get(theme, ['components', 'tooltip'], {});
var enterable = isUndefined(get(option, 'enterable')) ? defaultCfg.enterable : get(option, 'enterable');
return deepMix({}, defaultCfg, option, {
capture: enterable || this.isLocked ? true : false,
});
};
Tooltip.prototype.getTitle = function (items) {
var title = items[0].title || items[0].name;
this.title = title;
return title;
};
Tooltip.prototype.renderTooltip = function () {
var canvas = this.view.getCanvas();
var region = {
start: { x: 0, y: 0 },
end: { x: canvas.get('width'), y: canvas.get('height') },
};
var cfg = this.getTooltipCfg();
var tooltip = new HtmlTooltip(__assign(__assign({ parent: canvas.get('el').parentNode, region: region }, cfg), { visible: false, crosshairs: null }));
tooltip.init();
this.tooltip = tooltip;
};
Tooltip.prototype.renderTooltipMarkers = function (items, marker) {
var tooltipMarkersGroup = this.getTooltipMarkersGroup();
for (var _i = 0, items_3 = items; _i < items_3.length; _i++) {
var item = items_3[_i];
var x = item.x, y = item.y;
var attrs = __assign(__assign({ fill: item.color, symbol: 'circle', shadowColor: item.color }, marker), { x: x,
y: y });
tooltipMarkersGroup.addShape('marker', {
attrs: attrs,
});
}
};
Tooltip.prototype.renderCrosshairs = function (point, cfg) {
var crosshairsType = get(cfg, ['crosshairs', 'type'], 'x'); // 默认展示 x 轴上的辅助线
if (crosshairsType === 'x') {
if (this.yCrosshair) {
this.yCrosshair.hide();
}
this.renderXCrosshairs(point, cfg);
}
else if (crosshairsType === 'y') {
if (this.xCrosshair) {
this.xCrosshair.hide();
}
this.renderYCrosshairs(point, cfg);
}
else if (crosshairsType === 'xy') {
this.renderXCrosshairs(point, cfg);
this.renderYCrosshairs(point, cfg);
}
};
// 渲染 x 轴上的 tooltip 辅助线
Tooltip.prototype.renderXCrosshairs = function (point, tooltipCfg) {
var coordinate = this.getViewWithGeometry(this.view).getCoordinate();
if (!isPointInCoordinate(coordinate, point)) {
return;
}
var start;
var end;
if (coordinate.isRect) {
if (coordinate.isTransposed) {
start = {
x: coordinate.start.x,
y: point.y,
};
end = {
x: coordinate.end.x,
y: point.y,
};
}
else {
start = {
x: point.x,
y: coordinate.end.y,
};
end = {
x: point.x,
y: coordinate.start.y,
};
}
}
else {
// 极坐标下 x 轴上的 crosshairs 表现为半径
var angle = getAngleByPoint(coordinate, point);
var center = coordinate.getCenter();
var radius = coordinate.getRadius();
end = polarToCartesian(center.x, center.y, radius, angle);
start = center;
}
var cfg = deepMix({
start: start,
end: end,
container: this.getTooltipCrosshairsGroup(),
}, get(tooltipCfg, 'crosshairs', {}), this.getCrosshairsText('x', point, tooltipCfg));
delete cfg.type; // 与 Crosshairs 组件的 type 冲突故删除
var xCrosshair = this.xCrosshair;
if (xCrosshair) {
xCrosshair.update(cfg);
}
else {
xCrosshair = new Crosshair.Line(cfg);
xCrosshair.init();
}
xCrosshair.render();
xCrosshair.show();
this.xCrosshair = xCrosshair;
};
// 渲染 y 轴上的辅助线
Tooltip.prototype.renderYCrosshairs = function (point, tooltipCfg) {
var coordinate = this.getViewWithGeometry(this.view).getCoordinate();
if (!isPointInCoordinate(coordinate, point)) {
return;
}
var cfg;
var type;
if (coordinate.isRect) {
var start = void 0;
var end = void 0;
if (coordinate.isTransposed) {
start = {
x: point.x,
y: coordinate.end.y,
};
end = {
x: point.x,
y: coordinate.start.y,
};
}
else {
start = {
x: coordinate.start.x,
y: point.y,
};
end = {
x: coordinate.end.x,
y: point.y,
};
}
cfg = {
start: start,
end: end,
};
type = 'Line';
}
else {
// 极坐标下 y 轴上的 crosshairs 表现为圆弧
cfg = {
center: coordinate.getCenter(),
// @ts-ignore
radius: getDistanceToCenter(coordinate, point),
startAngle: coordinate.startAngle,
endAngle: coordinate.endAngle,
};
type = 'Circle';
}
cfg = deepMix({
container: this.getTooltipCrosshairsGroup()
}, cfg, get(tooltipCfg, 'crosshairs', {}), this.getCrosshairsText('y', point, tooltipCfg));
delete cfg.type; // 与 Crosshairs 组件的 type 冲突故删除
var yCrosshair = this.yCrosshair;
if (yCrosshair) {
// 如果坐标系发生直角坐标系与极坐标的切换操作
if ((coordinate.isRect && yCrosshair.get('type') === 'circle')
|| (!coordinate.isRect && yCrosshair.get('type') === 'line')) {
yCrosshair = new Crosshair[type](cfg);
yCrosshair.init();
}
else {
yCrosshair.update(cfg);
}
}
else {
yCrosshair = new Crosshair[type](cfg);
yCrosshair.init();
}
yCrosshair.render();
yCrosshair.show();
this.yCrosshair = yCrosshair;
};
Tooltip.prototype.getCrosshairsText = function (type, point, tooltipCfg) {
var textCfg = get(tooltipCfg, ['crosshairs', 'text']);
var follow = get(tooltipCfg, ['crosshairs', 'follow']);
var items = this.items;
if (textCfg) {
var view = this.getViewWithGeometry(this.view);
// 需要展示文本
var firstItem = items[0];
var xScale = view.getXScale();
var yScale = view.getYScales()[0];
var xValue = void 0;
var yValue = void 0;
if (follow) {
// 如果需要跟随鼠标移动,就需要将当前鼠标坐标点转换为对应的数值
var invertPoint = this.view.getCoordinate().invert(point);
xValue = xScale.invert(invertPoint.x); // 转换为原始值
yValue = yScale.invert(invertPoint.y); // 转换为原始值
}
else {
xValue = firstItem.data[xScale.field];
yValue = firstItem.data[yScale.field];
}
var content = type === 'x' ? xValue : yValue;
if (isFunction(textCfg)) {
textCfg = textCfg(type, content, items, point);
}
else {
textCfg.content = content;
}
return {
text: textCfg,
};
}
};
// 获取存储 tooltipMarkers 和 crosshairs 的容器
Tooltip.prototype.getGuideGroup = function () {
if (!this.guideGroup) {
var foregroundGroup = this.view.foregroundGroup;
this.guideGroup = foregroundGroup.addGroup({
name: 'tooltipGuide',
capture: false,
});
}
return this.guideGroup;
};
// 获取 tooltipMarkers 存储的容器
Tooltip.prototype.getTooltipMarkersGroup = function () {
var tooltipMarkersGroup = this.tooltipMarkersGroup;
if (tooltipMarkersGroup && !tooltipMarkersGroup.destroyed) {
tooltipMarkersGroup.clear();
tooltipMarkersGroup.show();
}
else {
tooltipMarkersGroup = this.getGuideGroup().addGroup({
name: 'tooltipMarkersGroup',
});
tooltipMarkersGroup.toFront();
this.tooltipMarkersGroup = tooltipMarkersGroup;
}
return tooltipMarkersGroup;
};
// 获取 tooltip crosshairs 存储的容器
Tooltip.prototype.getTooltipCrosshairsGroup = function () {
var tooltipCrosshairsGroup = this.tooltipCrosshairsGroup;
if (!tooltipCrosshairsGroup) {
tooltipCrosshairsGroup = this.getGuideGroup().addGroup({
name: 'tooltipCrosshairsGroup',
capture: false,
});
tooltipCrosshairsGroup.toBack();
this.tooltipCrosshairsGroup = tooltipCrosshairsGroup;
}
return tooltipCrosshairsGroup;
};
Tooltip.prototype.getTooltipItemsByHitShape = function (geometry, point, title) {
var result = [];
var container = geometry.container;
var shape = container.getShape(point.x, point.y);
if (shape && shape.get('visible') && shape.get('origin')) {
var mappingData = shape.get('origin').mappingData;
var items = getTooltipItems(mappingData, geometry, title);
if (items.length) {
result.push(items);
}
}
return result;
};
Tooltip.prototype.getTooltipItemsByFindData = function (geometry, point, title) {
var result = [];
var dataArray = geometry.dataArray;
geometry.sort(dataArray); // 先进行排序,便于 tooltip 查找
for (var _i = 0, dataArray_1 = dataArray; _i < dataArray_1.length; _i++) {
var data = dataArray_1[_i];
var record = findDataByPoint(point, data, geometry);
if (record) {
var elementId = geometry.getElementId(record);
var element = geometry.elementsMap[elementId];
if (geometry.type === 'heatmap' || element.visible) {
// Heatmap 没有 Element
// 如果图形元素隐藏了,怎不再 tooltip 上展示相关数据
var items = getTooltipItems(record, geometry, title);
if (items.length) {
result.push(items);
}
}
}
}
return result;
};
Tooltip.prototype.findItemsFromView = function (view, point) {
if (view.getOptions().tooltip === false) {
// 如果 view 关闭了 tooltip
return [];
}
var result = [];
// 先从 view 本身查找
var geometries = view.geometries;
var _a = this.getTooltipCfg(), shared = _a.shared, title = _a.title;
for (var _i = 0, geometries_1 = geometries; _i < geometries_1.length; _i++) {
var geometry = geometries_1[_i];
if (geometry.visible && geometry.tooltipOption !== false) {
// geometry 可见同时未关闭 tooltip
var geometryType = geometry.type;
var tooltipItems = void 0;
if (['point', 'edge', 'polygon'].includes(geometryType)) {
// 始终通过图形拾取
tooltipItems = this.getTooltipItemsByHitShape(geometry, point, title);
}
else if (['area', 'line', 'path', 'heatmap'].includes(geometryType)) {
// 如果是 'area', 'line', 'path',始终通过数据查找方法查找 tooltip
tooltipItems = this.getTooltipItemsByFindData(geometry, point, title);
}
else {
if (shared !== false) {
tooltipItems = this.getTooltipItemsByFindData(geometry, point, title);
}
else {
tooltipItems = this.getTooltipItemsByHitShape(geometry, point, title);
}
}
if (tooltipItems.length) {
// geometry 有可能会有多个 item因为用户可以设置 geometry.tooltip('x*y*z')
result.push(tooltipItems);
}
}
}
// 递归查找,并合并结果
for (var _b = 0, _c = view.views; _b < _c.length; _b++) {
var childView = _c[_b];
result = result.concat(this.findItemsFromView(childView, point));
}
return result;
};
// FIXME: hack 方法
// 因为 tooltip 的交互是挂载在 Chart 上所以当chart 上没有绘制 Geometry 的时候,就查找不到数据,并且绘图区域同子 View 的区域不同
Tooltip.prototype.getViewWithGeometry = function (view) {
var _this = this;
if (view.geometries.length) {
return view;
}
return find(view.views, function (childView) { return _this.getViewWithGeometry(childView); });
};
return Tooltip;
}(Controller));
export default Tooltip;
//# sourceMappingURL=tooltip.js.map