function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
/**
* @fileOverview The class of tooltip
* @author sima.zhang
*/
var Util = require('../../util');
var Base = require('../../base');
var Global = require('../../global');
var DomUtil = Util.DomUtil;
var CONTAINER_CLASS = 'g2-tooltip';
var TITLE_CLASS = 'g2-tooltip-title';
var LIST_CLASS = 'g2-tooltip-list';
var MARKER_CLASS = 'g2-tooltip-marker';
var VALUE_CLASS = 'g2-tooltip-value';
var LIST_ITEM_CLASS = 'g2-tooltip-list-item';
function find(dom, cls) {
return dom.getElementsByClassName(cls)[0];
}
function refixTooltipPosition(x, y, el, viewWidth, viewHeight) {
var width = el.clientWidth;
var height = el.clientHeight;
var gap = 20;
if (x + width + gap > viewWidth) {
x -= width + gap;
x = x < 0 ? 0 : x;
} else {
x += gap;
}
if (y + height + gap > viewHeight) {
y -= height + gap;
y = x < 0 ? 0 : y;
} else {
y += gap;
}
return [x, y];
}
function calcTooltipPosition(x, y, position, dom, target) {
var domWidth = dom.clientWidth;
var domHeight = dom.clientHeight;
var rectWidth = 0;
var rectHeight = 0;
var gap = 20;
if (target) {
var rect = target.getBBox();
rectWidth = rect.width;
rectHeight = rect.height;
x = rect.x;
y = rect.y;
gap = 5;
}
switch (position) {
case 'inside':
x = x + rectWidth / 2 - domWidth / 2;
y = y + rectHeight / 2 - domHeight / 2;
break;
case 'top':
x = x + rectWidth / 2 - domWidth / 2;
y = y - domHeight - gap;
break;
case 'left':
x = x - domWidth - gap;
y = y + rectHeight / 2 - domHeight / 2;
break;
case 'right':
x = x + rectWidth + gap;
y = y + rectHeight / 2 - domHeight / 2;
break;
case 'bottom':
default:
x = x + rectWidth / 2 - domWidth / 2;
y = y + rectHeight + gap;
break;
}
return [x, y];
}
function confineTooltipPosition(x, y, el, plotRange, onlyHorizontal) {
var gap = 20;
var width = el.clientWidth;
var height = el.clientHeight;
if (x + width > plotRange.tr.x) {
x -= width + 2 * gap;
}
if (x < plotRange.tl.x) {
x = plotRange.tl.x;
}
if (!onlyHorizontal) {
if (y + height > plotRange.bl.y) {
y -= height + 2 * gap;
}
if (y < plotRange.tl.y) {
y = plotRange.tl.y;
}
}
return [x, y];
}
var Tooltip = /*#__PURE__*/function (_Base) {
_inheritsLoose(Tooltip, _Base);
var _proto = Tooltip.prototype;
_proto.getDefaultCfg = function getDefaultCfg() {
return {
/**
* 右下角坐标
* @type {Number}
*/
x: 0,
/**
* y 右下角坐标
* @type {Number}
*/
y: 0,
/**
* tooltip 记录项
* @type {Array}
*/
items: null,
/**
* 是否展示 title
* @type {Boolean}
*/
showTitle: true,
/**
* tooltip 辅助线配置
* @type {Object}
*/
crosshairs: null,
/**
* 视图范围
* @type {Object}
*/
plotRange: null,
/**
* x轴上,移动到位置的偏移量
* @type {Number}
*/
offset: 10,
/**
* 时间戳
* @type {Number}
*/
timeStamp: 0,
/**
* tooltip 容器模板
* @type {String}
*/
containerTpl: '
',
/**
* tooltip 列表项模板
* @type {String}
*/
itemTpl: '' + '' + '{name}{value}',
/**
* 将 tooltip 展示在指定区域内
* @type {Boolean}
*/
inPlot: true,
/**
* tooltip 内容跟随鼠标移动
* @type {Boolean}
*/
follow: true,
/**
* 是否允许鼠标停留在 tooltip 上,默认不允许
* @type {Boolean}
*/
enterable: false,
/**
* 设置几何体对应的maker
*/
marker: null
};
};
_proto._initTooltipWrapper = function _initTooltipWrapper() {
var self = this;
var containerTpl = self.get('containerTpl');
var outterNode = self.get('canvas').get('el').parentNode;
var container;
if (/^\#/.test(containerTpl)) {
// 如果传入 dom 节点的 id
var id = containerTpl.replace('#', '');
container = document.getElementById(id);
} else {
container = DomUtil.createDom(containerTpl);
DomUtil.modifyCSS(container, self.get(CONTAINER_CLASS));
outterNode.appendChild(container);
outterNode.style.position = 'relative';
}
self.set('container', container);
};
_proto._init = function _init() {
var crosshairs = this.get('crosshairs');
var frontPlot = this.get('frontPlot');
var backPlot = this.get('backPlot');
var viewTheme = this.get('viewTheme') || Global;
var crosshairsGroup;
if (crosshairs) {
if (crosshairs.type === 'rect') {
this.set('crosshairs', Util.deepMix({}, viewTheme.tooltipCrosshairsRect, crosshairs));
crosshairsGroup = backPlot.addGroup({
zIndex: 0
});
} else {
this.set('crosshairs', Util.deepMix({}, viewTheme.tooltipCrosshairsLine, crosshairs));
crosshairsGroup = frontPlot.addGroup();
}
}
this.set('crosshairsGroup', crosshairsGroup);
this._initTooltipWrapper();
};
function Tooltip(cfg) {
var _this;
_this = _Base.call(this, cfg) || this;
_this._init(); // 初始化属性
if (_this.get('items')) {
_this._renderTooltip();
}
_this._renderCrosshairs();
return _this;
}
_proto._clearDom = function _clearDom() {
var container = this.get('container');
var titleDom = find(container, TITLE_CLASS);
var listDom = find(container, LIST_CLASS);
if (titleDom) {
titleDom.innerHTML = '';
}
if (listDom) {
listDom.innerHTML = '';
}
};
_proto._addItem = function _addItem(item, index) {
var itemTpl = this.get('itemTpl'); // TODO: 有可能是个回调函数
var itemDiv = Util.substitute(itemTpl, Util.mix({
index: index
}, item));
var itemDOM = DomUtil.createDom(itemDiv);
DomUtil.modifyCSS(itemDOM, this.get(LIST_ITEM_CLASS));
var markerDom = find(itemDOM, MARKER_CLASS);
if (markerDom) {
DomUtil.modifyCSS(markerDom, this.get(MARKER_CLASS));
}
var valueDom = find(itemDOM, VALUE_CLASS);
if (valueDom) {
DomUtil.modifyCSS(valueDom, this.get(VALUE_CLASS));
}
return itemDOM;
};
_proto._renderTooltip = function _renderTooltip() {
var self = this;
var showTitle = self.get('showTitle');
var titleContent = self.get('titleContent');
var container = self.get('container');
var titleDom = find(container, TITLE_CLASS);
var listDom = find(container, LIST_CLASS);
var items = self.get('items');
self._clearDom();
if (titleDom && showTitle) {
DomUtil.modifyCSS(titleDom, self.get(TITLE_CLASS));
titleDom.innerHTML = titleContent;
}
if (listDom) {
DomUtil.modifyCSS(listDom, self.get(LIST_CLASS));
Util.each(items, function (item, index) {
listDom.appendChild(self._addItem(item, index));
});
}
};
_proto._clearCrosshairsGroup = function _clearCrosshairsGroup() {
var crosshairsGroup = this.get('crosshairsGroup');
this.set('crossLineShapeX', null);
this.set('crossLineShapeY', null);
this.set('crosshairsRectShape', null);
crosshairsGroup.clear();
};
_proto._renderCrosshairs = function _renderCrosshairs() {
var crosshairs = this.get('crosshairs');
var canvas = this.get('canvas');
var plotRange = this.get('plotRange');
var isTransposed = this.get('isTransposed');
if (crosshairs) {
this._clearCrosshairsGroup();
switch (crosshairs.type) {
case 'x':
this._renderHorizontalLine(canvas, plotRange);
break;
case 'y':
this._renderVerticalLine(canvas, plotRange);
break;
case 'cross':
this._renderHorizontalLine(canvas, plotRange);
this._renderVerticalLine(canvas, plotRange);
break;
case 'rect':
this._renderBackground(canvas, plotRange);
break;
default:
isTransposed ? this._renderHorizontalLine(canvas, plotRange) : this._renderVerticalLine(canvas, plotRange);
}
}
};
_proto._addCrossLineShape = function _addCrossLineShape(attrs, type) {
var crosshairsGroup = this.get('crosshairsGroup');
var shape = crosshairsGroup.addShape('line', {
capture: false,
attrs: attrs
});
shape.hide();
this.set('crossLineShape' + type, shape);
return shape;
};
_proto._renderVerticalLine = function _renderVerticalLine(canvas, plotRange) {
var _this$get = this.get('crosshairs'),
style = _this$get.style;
var attrs = Util.mix({
x1: 0,
y1: plotRange ? plotRange.bl.y : canvas.get('height'),
x2: 0,
y2: plotRange ? plotRange.tl.y : 0
}, style);
this._addCrossLineShape(attrs, 'Y');
};
_proto._renderHorizontalLine = function _renderHorizontalLine(canvas, plotRange) {
var _this$get2 = this.get('crosshairs'),
style = _this$get2.style;
var attrs = Util.mix({
x1: plotRange ? plotRange.bl.x : canvas.get('width'),
y1: 0,
x2: plotRange ? plotRange.br.x : 0,
y2: 0
}, style);
this._addCrossLineShape(attrs, 'X');
};
_proto._renderBackground = function _renderBackground(canvas, plotRange) {
var _this$get3 = this.get('crosshairs'),
style = _this$get3.style;
var crosshairsGroup = this.get('crosshairsGroup');
var attrs = Util.mix({
x: plotRange ? plotRange.tl.x : 0,
y: plotRange ? plotRange.tl.y : canvas.get('height'),
width: plotRange ? plotRange.br.x - plotRange.bl.x : canvas.get('width'),
height: plotRange ? Math.abs(plotRange.tl.y - plotRange.bl.y) : canvas.get('height')
}, style);
var shape = crosshairsGroup.addShape('rect', {
attrs: attrs
});
shape.hide();
this.set('crosshairsRectShape', shape);
return shape;
};
_proto.isContentChange = function isContentChange(title, items) {
var titleContent = this.get('titleContent');
var lastItems = this.get('items');
var isChanged = !(title === titleContent && lastItems.length === items.length);
if (!isChanged) {
Util.each(items, function (item, index) {
var preItem = lastItems[index];
for (var key in item) {
if (item.hasOwnProperty(key)) {
if (!Util.isObject(item[key]) && item[key] !== preItem[key]) {
isChanged = true;
break;
}
}
} // isChanged = (item.value !== preItem.value) || (item.color !== preItem.color) || (item.name !== preItem.name) || (item.title !== preItem.title);
if (isChanged) {
return false;
}
});
}
return isChanged;
};
_proto.setContent = function setContent(title, items) {
// const isChange = this.isContentChange(title, items);
// if (isChange) {
// 在外面进行判断是否内容发生改变
var timeStamp = +new Date();
this.set('items', items);
this.set('titleContent', title);
this.set('timeStamp', timeStamp);
this._renderTooltip(); // }
return this;
};
_proto.setMarkers = function setMarkers(markerItems, markerCfg) {
var self = this;
var markerGroup = self.get('markerGroup');
var frontPlot = self.get('frontPlot');
if (!markerGroup) {
markerGroup = frontPlot.addGroup({
zIndex: 1,
capture: false // 不进行拾取
});
self.set('markerGroup', markerGroup);
} else {
markerGroup.clear();
}
Util.each(markerItems, function (item) {
markerGroup.addShape('marker', {
color: item.color,
attrs: Util.mix({
// fix: Theme.tooltipMarker invalid
fill: item.color,
symbol: 'circle',
shadowColor: item.color
}, markerCfg, {
x: item.x,
y: item.y,
symbol: item.symbol
})
});
});
this.set('markerItems', markerItems);
};
_proto.clearMarkers = function clearMarkers() {
var markerGroup = this.get('markerGroup');
markerGroup && markerGroup.clear();
};
_proto.setPosition = function setPosition(x, y, target) {
var container = this.get('container'); // 修复tooltip初始位置错误,是由于container隐藏时获取不到宽高导致
// 记住上次可见性
var lastVisibility = container.style.visibility;
var lastDisplay = container.style.display; // 设为可见
container.style.visibility = 'visible';
container.style.display = 'block';
var crossLineShapeX = this.get('crossLineShapeX');
var crossLineShapeY = this.get('crossLineShapeY');
var crosshairsRectShape = this.get('crosshairsRectShape');
var endx = x;
var endy = y; // const outterNode = this.get('canvas').get('el').parentNode;
var outterNode = this.get('canvas').get('el');
var viewWidth = DomUtil.getWidth(outterNode);
var viewHeight = DomUtil.getHeight(outterNode);
var offset = this.get('offset');
var position;
var prePosition = this.get('prePosition') || {
x: 0,
y: 0
};
if (this.get('position')) {
position = calcTooltipPosition(x, y, this.get('position'), container, target);
x = position[0];
y = position[1];
} else if (this.get('enterable')) {
y = y - container.clientHeight / 2;
position = {
x: x,
y: y
};
if (prePosition && x - prePosition.x > 0) {
// 留 1px 防止鼠标点击事件无法在画布上触发
x -= container.clientWidth + 1;
} else {
x += 1;
}
} else {
position = refixTooltipPosition(x, y, container, viewWidth, viewHeight);
x = position[0];
y = position[1];
}
this.set('prePosition', position); // 记录上次的位置
if (this.get('inPlot')) {
// tooltip 必须限制在绘图区域内
var plotRange = this.get('plotRange');
position = confineTooltipPosition(x, y, container, plotRange, this.get('enterable'));
x = position[0];
y = position[1];
}
if (prePosition.x !== x || prePosition.y !== y) {
var markerItems = this.get('markerItems');
if (!Util.isEmpty(markerItems)) {
endx = markerItems[0].x;
endy = markerItems[0].y;
}
if (crossLineShapeY) {
// 第一次进入时,画布需要单独绘制,所以需要先设定corss的位置
crossLineShapeY.move(endx, 0);
}
if (crossLineShapeX) {
crossLineShapeX.move(0, endy);
}
if (crosshairsRectShape) {
// 绘制矩形辅助框,只在直角坐标系下生效
var isTransposed = this.get('isTransposed');
var items = this.get('items');
var firstItem = items[0];
var lastItem = items[items.length - 1];
var dim = isTransposed ? 'y' : 'x';
var attr = isTransposed ? 'height' : 'width';
var startDim = firstItem[dim];
if (items.length > 1 && firstItem[dim] > lastItem[dim]) {
startDim = lastItem[dim];
}
if (this.get('crosshairs').width) {
// 用户定义了 width
crosshairsRectShape.attr(dim, startDim - this.get('crosshairs').width / 2);
crosshairsRectShape.attr(attr, this.get('crosshairs').width);
} else {
if (Util.isArray(firstItem.point[dim]) && !firstItem.size) {
// 直方图
var width = firstItem.point[dim][1] - firstItem.point[dim][0];
crosshairsRectShape.attr(dim, firstItem.point[dim][0]);
crosshairsRectShape.attr(attr, width);
} else {
offset = 3 * firstItem.size / 4;
crosshairsRectShape.attr(dim, startDim - offset);
if (items.length === 1) {
crosshairsRectShape.attr(attr, 3 * firstItem.size / 2);
} else {
crosshairsRectShape.attr(attr, Math.abs(lastItem[dim] - firstItem[dim]) + 2 * offset);
}
}
}
}
var follow = this.get('follow');
container.style.left = follow ? x + 'px' : 0;
container.style.top = follow ? y + 'px' : 0;
} // 设为可见
container.style.visibility = lastVisibility;
container.style.display = lastDisplay;
};
_proto.show = function show() {
var crossLineShapeX = this.get('crossLineShapeX');
var crossLineShapeY = this.get('crossLineShapeY');
var crosshairsRectShape = this.get('crosshairsRectShape');
var markerGroup = this.get('markerGroup');
var container = this.get('container');
var canvas = this.get('canvas');
crossLineShapeX && crossLineShapeX.show();
crossLineShapeY && crossLineShapeY.show();
crosshairsRectShape && crosshairsRectShape.show();
markerGroup && markerGroup.show();
_Base.prototype.show.call(this);
container.style.visibility = 'visible'; // canvas.sort();
canvas.draw();
};
_proto.hide = function hide() {
var self = this;
var container = self.get('container');
if (container && container.style) {
var crossLineShapeX = self.get('crossLineShapeX');
var crossLineShapeY = self.get('crossLineShapeY');
var crosshairsRectShape = this.get('crosshairsRectShape');
var markerGroup = self.get('markerGroup');
var canvas = self.get('canvas');
container.style.visibility = 'hidden';
crossLineShapeX && crossLineShapeX.hide();
crossLineShapeY && crossLineShapeY.hide();
crosshairsRectShape && crosshairsRectShape.hide();
markerGroup && markerGroup.hide();
_Base.prototype.hide.call(this);
canvas.draw();
}
};
_proto.destroy = function destroy() {
var self = this;
var crossLineShapeX = self.get('crossLineShapeX');
var crossLineShapeY = self.get('crossLineShapeY');
var markerGroup = self.get('markerGroup');
var crosshairsRectShape = self.get('crosshairsRectShape');
var container = self.get('container');
var containerTpl = self.get('containerTpl');
if (container && !/^\#/.test(containerTpl)) {
container.parentNode.removeChild(container);
}
crossLineShapeX && crossLineShapeX.remove();
crossLineShapeY && crossLineShapeY.remove();
markerGroup && markerGroup.remove();
crosshairsRectShape && crosshairsRectShape.remove(); // super.remove();
_Base.prototype.destroy.call(this);
};
return Tooltip;
}(Base);
module.exports = Tooltip;