NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/lib/chart/controller/tooltip.js
2023-09-14 14:47:11 +08:00

630 lines
18 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/**
* @fileOverview The controller of tooltip
* @author sima.zhang
*/
var Util = require('../../util');
var Shape = require('../../geom/shape/shape');
var _require = require('@antv/component/lib'),
Tooltip = _require.Tooltip;
var MatrixUtil = Util.MatrixUtil;
var Vector2 = MatrixUtil.vec2;
var TYPE_SHOW_MARKERS = ['line', 'area', 'path', 'areaStack']; // 默认展示 tooltip marker 的几何图形
var TYPE_SHOW_CROSSHAIRS = ['line', 'area', 'point']; // 默认展示十字瞄准线的几何图形
// TODO FIXME this is HARD CODING
var IGNORE_TOOLTIP_ITEM_PROPERTIES = ['marker', 'showMarker'];
function _indexOfArray(items, item) {
var rst = -1;
Util.each(items, function (sub, index) {
var isEqual = true;
for (var key in item) {
if (item.hasOwnProperty(key) && !IGNORE_TOOLTIP_ITEM_PROPERTIES.includes(key)) {
if (!Util.isObject(item[key]) && item[key] !== sub[key]) {
isEqual = false;
break;
}
}
}
if (isEqual) {
rst = index;
return false;
}
});
return rst;
} // 判断是否有样式
function _hasClass(dom, className) {
if (!dom) {
return false;
}
var cls = '';
if (!dom.className) return false;
if (!Util.isNil(dom.className.baseVal)) {
cls = dom.className.baseVal;
} else {
cls = dom.className;
}
return cls.includes(className);
}
function _isParent(dom, cls) {
var parent = dom.parentNode;
var rst = false;
while (parent && parent !== document.body) {
if (_hasClass(parent, cls)) {
rst = true;
break;
}
parent = parent.parentNode;
}
return rst;
} // 去除重复的值, 去除不同图形相同数据,只展示一份即可
function _uniqItems(items) {
var tmp = [];
Util.each(items, function (item) {
var index = _indexOfArray(tmp, item);
if (index === -1) {
tmp.push(item);
} else {
tmp[index] = item;
}
});
return tmp;
}
var TooltipController = /*#__PURE__*/function () {
function TooltipController(cfg) {
Util.assign(this, cfg);
this.timeStamp = 0; // tooltip 锁定不能移动
this.locked = false;
}
var _proto = TooltipController.prototype;
_proto._normalizeEvent = function _normalizeEvent(event) {
var chart = this.chart;
var canvas = this._getCanvas();
var point = canvas.getPointByClient(event.clientX, event.clientY);
var pixelRatio = canvas.get('pixelRatio');
point.x = point.x / pixelRatio;
point.y = point.y / pixelRatio;
var views = chart.getViewsByPoint(point);
point.views = views;
return point;
};
_proto._getCanvas = function _getCanvas() {
return this.chart.get('canvas');
};
_proto._getTriggerEvent = function _getTriggerEvent() {
var options = this.options;
var triggerOn = options.triggerOn;
var eventName;
if (!triggerOn || triggerOn === 'mousemove') {
eventName = 'plotmove';
} else if (triggerOn === 'click') {
eventName = 'plotclick';
} else if (triggerOn === 'none') {
eventName = null;
}
return eventName;
};
_proto._getDefaultTooltipCfg = function _getDefaultTooltipCfg() {
var self = this;
var chart = self.chart;
var viewTheme = self.viewTheme;
var options = self.options;
var defaultCfg = Util.mix({}, viewTheme.tooltip);
var geoms = chart.getAllGeoms().filter(function (geom) {
return geom.get('visible');
});
var shapes = [];
Util.each(geoms, function (geom) {
var type = geom.get('type');
var adjusts = geom.get('adjusts');
var isSymmetric = false;
if (adjusts) {
Util.each(adjusts, function (adjust) {
if (adjust.type === 'symmetric' || adjust.type === 'Symmetric') {
isSymmetric = true;
return false;
}
});
}
if (Util.indexOf(shapes, type) === -1 && !isSymmetric) {
shapes.push(type);
}
});
var isTransposed = geoms.length && geoms[0].get('coord') ? geoms[0].get('coord').isTransposed : false;
var crosshairsCfg;
if (geoms.length && geoms[0].get('coord') && geoms[0].get('coord').type === 'cartesian') {
if (shapes[0] === 'interval' && options.shared !== false) {
// 直角坐标系下 interval 的 crosshair 为矩形背景框
var crosshairs = Util.mix({}, viewTheme.tooltipCrosshairsRect);
crosshairs.isTransposed = isTransposed;
crosshairsCfg = {
zIndex: 0,
// 矩形背景框不可覆盖 geom
crosshairs: crosshairs
};
} else if (Util.indexOf(TYPE_SHOW_CROSSHAIRS, shapes[0]) > -1) {
var _crosshairs = Util.mix({}, viewTheme.tooltipCrosshairsLine);
_crosshairs.isTransposed = isTransposed;
crosshairsCfg = {
crosshairs: _crosshairs
};
}
}
return Util.mix(defaultCfg, crosshairsCfg, {});
};
_proto._bindEvent = function _bindEvent() {
var chart = this.chart;
var triggerEvent = this._getTriggerEvent();
if (triggerEvent) {
chart.on(triggerEvent, Util.wrapBehavior(this, 'onMouseMove'));
chart.on('plotleave', Util.wrapBehavior(this, 'onMouseOut'));
}
};
_proto._offEvent = function _offEvent() {
var chart = this.chart;
var triggerEvent = this._getTriggerEvent();
if (triggerEvent) {
chart.off(triggerEvent, Util.getWrapBehavior(this, 'onMouseMove'));
chart.off('plotleave', Util.getWrapBehavior(this, 'onMouseOut'));
}
};
_proto._setTooltip = function _setTooltip(point, items, markersItems, target) {
var self = this;
var tooltip = self.tooltip;
var prePoint = self.prePoint;
if (!prePoint || prePoint.x !== point.x || prePoint.y !== point.y) {
items = _uniqItems(items);
self.prePoint = point;
var chart = self.chart;
var viewTheme = self.viewTheme;
var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;
if (!tooltip.get('visible')) {
chart.emit('tooltip:show', {
x: x,
y: y,
tooltip: tooltip
});
}
var first = items[0];
var title = first.title || first.name;
if (tooltip.isContentChange(title, items)) {
chart.emit('tooltip:change', {
tooltip: tooltip,
x: x,
y: y,
items: items
}); // bugfix: when set the title in the tooltip:change event does not take effect.
title = items[0].title || items[0].name;
tooltip.setContent(title, items);
if (!Util.isEmpty(markersItems)) {
if (self.options.hideMarkers === true) {
// 不展示 tooltip marker
tooltip.set('markerItems', markersItems); // 用于 tooltip 辅助线的定位
} else {
tooltip.setMarkers(markersItems, viewTheme.tooltipMarker);
}
} else {
tooltip.clearMarkers(); // clearMarkers 只会将 markerItems 从 markerGroup 中移除
// 所以我们还要将 markerItems 从 tooltip 中移除
// 这么做是为了防止上一次设置 marker 时的 markerItems 影响此次 tooltip 辅助线的定位
tooltip.set('markerItems', []);
}
}
var canvas = this._getCanvas();
if (target === canvas && tooltip.get('type') === 'mini') {
// filter mini tooltip
tooltip.hide();
} else {
tooltip.setPosition(x, y, target);
tooltip.show();
}
}
};
_proto.hideTooltip = function hideTooltip() {
var tooltip = this.tooltip;
var chart = this.chart;
var canvas = this._getCanvas();
this.prePoint = null;
tooltip.hide();
chart.emit('tooltip:hide', {
tooltip: tooltip
});
canvas.draw();
};
_proto.onMouseMove = function onMouseMove(ev) {
// 锁定时不移动 tooltip
if (Util.isEmpty(ev.views) || this.locked) {
return;
}
var lastTimeStamp = this.timeStamp;
var timeStamp = +new Date();
var point = {
x: ev.x,
y: ev.y
};
if (timeStamp - lastTimeStamp > 16 && !this.chart.get('stopTooltip')) {
this.showTooltip(point, ev.views, ev.shape);
this.timeStamp = timeStamp;
}
};
_proto.onMouseOut = function onMouseOut(ev) {
var tooltip = this.tooltip; // 锁定 tooltip 时不隐藏
if (!tooltip.get('visible') || !tooltip.get('follow') || this.locked) {
return;
} // 除非离开 plot 时鼠标依然在图形上,这段逻辑没有意义
// if (ev && ev.target !== canvas) {
// return;
// }
if (ev && ev.toElement && (_hasClass(ev.toElement, 'g2-tooltip') || _isParent(ev.toElement, 'g2-tooltip'))) {
return;
}
this.hideTooltip();
};
_proto.renderTooltip = function renderTooltip() {
var self = this;
if (self.tooltip) {
// tooltip 对象已经创建
return;
}
var chart = self.chart;
var viewTheme = self.viewTheme;
var canvas = self._getCanvas();
var defaultCfg = self._getDefaultTooltipCfg();
var options = self.options;
options = Util.deepMix({
plotRange: chart.get('plotRange'),
capture: false,
canvas: canvas,
frontPlot: chart.get('frontPlot'),
viewTheme: viewTheme.tooltip,
backPlot: chart.get('backPlot')
}, defaultCfg, options);
if (options.crosshairs && options.crosshairs.type === 'rect') {
options.zIndex = 0; // toolip 背景框不可遮盖住 geom防止用户配置了 crosshairs
}
options.visible = false; // @2018-09-13 by blue.lb 如果设置shared为false不需要指定position
// if (options.shared === false && Util.isNil(options.position)) {
// options.position = 'top';
// }
var tooltip;
if (options.type === 'mini') {
options.crosshairs = false; // this.options.shared = false;
options.position = 'top';
tooltip = new Tooltip.Mini(options);
} else if (options.useHtml) {
tooltip = new Tooltip.Html(options);
} else {
tooltip = new Tooltip.Canvas(options);
}
self.tooltip = tooltip;
var triggerEvent = self._getTriggerEvent();
var tooltipContainer = tooltip.get('container');
if (!tooltip.get('enterable') && triggerEvent === 'plotmove') {
// 鼠标不允许进入 tooltip 容器
if (tooltipContainer) {
tooltipContainer.onmousemove = function (e) {
// 避免 tooltip 频繁闪烁
var eventObj = self._normalizeEvent(e);
chart.emit(triggerEvent, eventObj);
};
}
} // 优化:鼠标移入 tooltipContainer 然后再移出时,需要隐藏 tooltip
if (tooltipContainer) {
tooltipContainer.onmouseleave = function () {
if (!self.locked) {
self.hideTooltip();
}
};
}
self._bindEvent();
};
_proto._formatMarkerOfItem = function _formatMarkerOfItem(coord, geom, item) {
var self = this;
var options = self.options;
var point = item.point;
if (point && point.x && point.y) {
// hotfix: make sure there is no null value
var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;
point = coord.applyMatrix(x, y, 1);
item.x = point[0];
item.y = point[1];
item.showMarker = true; // bugfix
// 由于tooltip是DOM而不是Canvas设置渐变色时marker无法正常显示
// 如果设置的颜色是渐变色并且设置了tooltip使用html方式渲染则取渐变色的起始颜色作为marker的颜色暂时解决这个问题
if (item.color.substring(0, 2) === 'l(' && (!options.hasOwnProperty('useHtml') || options.useHtml)) {
item.color = item.color.split(' ')[1].substring(2);
}
var itemMarker = self._getItemMarker(geom, item);
item.marker = itemMarker;
if (Util.indexOf(TYPE_SHOW_MARKERS, geom.get('type')) !== -1) {
return item;
}
}
return null;
};
_proto.lockTooltip = function lockTooltip() {
this.locked = true;
};
_proto.unlockTooltip = function unlockTooltip() {
this.locked = false;
};
_proto.showTooltip = function showTooltip(point, views, target) {
var _this = this;
var self = this;
if (Util.isEmpty(views) || !point) {
return;
}
if (!this.tooltip) {
this.renderTooltip(); // 如果一开始 tooltip 关闭,用户重新调用的时候需要先生成 tooltip
}
var options = self.options;
var markersItems = [];
var items = [];
Util.each(views, function (view) {
if (!view.get('tooltipEnable')) {
// 如果不显示tooltip则跳过
return true;
}
var geoms = view.get('geoms');
var coord = view.get('coord');
Util.each(geoms, function (geom) {
var type = geom.get('type');
if (geom.get('visible') && geom.get('tooltipCfg') !== false) {
var dataArray = geom.get('dataArray');
if (geom.isShareTooltip() || options.shared === false && Util.inArray(['area', 'line', 'path', 'polygon'], type)) {
// 打补丁解决 bug: https://github.com/antvis/g2/issues/1248
// 当 interval 对应的 color 和 x 字段相同的时候,并且包含 dodgeitems 取值逻辑不一样
// 这种情况下,每一个 x 字段分成一组
var xScale = geom.getXScale();
var colorAttr = geom.getAttr('color');
var colorField = colorAttr ? colorAttr.field : undefined;
if (type === 'interval' && xScale.field === colorField && geom.hasAdjust('dodge')) {
// 找不到不为空的
var points = Util.find(dataArray, function (obj) {
return !!geom.findPoint(point, obj);
}); // 转为 tooltip items
Util.each(points, function (tmpPoint) {
var subItems = geom.getTipItems(tmpPoint, options.title);
Util.each(subItems, function (v) {
var markerItem = self._formatMarkerOfItem(coord, geom, v);
if (markerItem) {
markersItems.push(markerItem);
}
});
items = items.concat(subItems);
});
} else {
Util.each(dataArray, function (obj) {
var tmpPoint = geom.findPoint(point, obj);
if (tmpPoint) {
var subItems = geom.getTipItems(tmpPoint, options.title);
Util.each(subItems, function (v) {
var markerItem = self._formatMarkerOfItem(coord, geom, v);
if (markerItem) {
markersItems.push(markerItem);
}
});
items = items.concat(subItems);
}
});
}
} else {
var geomContainer = geom.get('shapeContainer');
var canvas = geomContainer.get('canvas');
var pixelRatio = canvas.get('pixelRatio');
var shape = geomContainer.getShape(point.x * pixelRatio, point.y * pixelRatio);
if (shape && shape.get('visible') && shape.get('origin')) {
items = geom.getTipItems(shape.get('origin'), options.title);
}
Util.each(items, function (v) {
var markerItem = _this._formatMarkerOfItem(coord, geom, v);
if (markerItem) {
markersItems.push(markerItem);
}
});
}
}
});
Util.each(items, function (item) {
var point = item.point;
var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;
point = coord.applyMatrix(x, y, 1);
item.x = point[0];
item.y = point[1];
});
});
if (items.length) {
var first = items[0]; // bugfix: multiple tooltip items with different titles
if (!items.every(function (item) {
return item.title === first.title;
})) {
var nearestItem = first;
var nearestDistance = Infinity;
items.forEach(function (item) {
var distance = Vector2.distance([point.x, point.y], [item.x, item.y]);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestItem = item;
}
});
items = items.filter(function (item) {
return item.title === nearestItem.title;
});
markersItems = markersItems.filter(function (item) {
return item.title === nearestItem.title;
});
}
if (options.shared === false && items.length > 1) {
var snapItem = items[0];
var min = Math.abs(point.y - snapItem.y);
Util.each(items, function (aItem) {
if (Math.abs(point.y - aItem.y) <= min) {
snapItem = aItem;
min = Math.abs(point.y - aItem.y);
}
});
if (snapItem && snapItem.x && snapItem.y) {
markersItems = [snapItem];
}
items = [snapItem];
} // 3.0 采用当前鼠标位置作为 tooltip 的参考点
// if (!Util.isEmpty(markersItems)) {
// point = markersItems[0];
// }
self._setTooltip(point, items, markersItems, target);
} else {
self.hideTooltip();
}
};
_proto.clear = function clear() {
var tooltip = this.tooltip;
tooltip && tooltip.destroy();
this.tooltip = null;
this.prePoint = null;
this._offEvent();
};
_proto._getItemMarker = function _getItemMarker(geom, item) {
var options = this.options;
var markerOption = options.marker || this.viewTheme.tooltip.marker;
if (Util.isFunction(markerOption)) {
var shapeType = geom.get('shapeType') || 'point';
var shape = geom.getDefaultValue('shape') || 'circle';
var shapeObject = Shape.getShapeFactory(shapeType);
var cfg = {
color: item.color
};
var marker = shapeObject.getMarkerCfg(shape, cfg);
return markerOption(marker, item);
}
return _extends({
fill: item.color
}, markerOption);
};
return TooltipController;
}();
module.exports = TooltipController;