403 lines
12 KiB
JavaScript
403 lines
12 KiB
JavaScript
![]() |
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); }
|
|||
|
|
|||
|
function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|||
|
|
|||
|
function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
|||
|
|
|||
|
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
|||
|
|
|||
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|||
|
|
|||
|
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|||
|
|
|||
|
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
|
|||
|
|
|||
|
var G = require('@antv/g/lib');
|
|||
|
|
|||
|
var Tooltip = require('./base');
|
|||
|
|
|||
|
var Util = require('../util');
|
|||
|
|
|||
|
var DomUtil = Util.DomUtil;
|
|||
|
|
|||
|
var TooltipTheme = require('./theme');
|
|||
|
|
|||
|
var Crosshair = require('./crosshair');
|
|||
|
|
|||
|
var PositionMixin = require('./mixin/position');
|
|||
|
|
|||
|
var MarkerGroupMixin = require('./mixin/marker-group');
|
|||
|
|
|||
|
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';
|
|||
|
var MARKER_SIZE = 5;
|
|||
|
var Marker = G.Marker;
|
|||
|
|
|||
|
function find(dom, cls) {
|
|||
|
return dom.getElementsByClassName(cls)[0];
|
|||
|
}
|
|||
|
|
|||
|
function mergeStyles(styles, cfg) {
|
|||
|
Object.keys(styles).forEach(function (k) {
|
|||
|
if (cfg[k]) {
|
|||
|
styles[k] = Util.mix(styles[k], cfg[k]);
|
|||
|
}
|
|||
|
});
|
|||
|
return styles;
|
|||
|
}
|
|||
|
|
|||
|
var HtmlTooltip = /*#__PURE__*/function (_Tooltip) {
|
|||
|
_inheritsLoose(HtmlTooltip, _Tooltip);
|
|||
|
|
|||
|
var _super = _createSuper(HtmlTooltip);
|
|||
|
|
|||
|
var _proto = HtmlTooltip.prototype;
|
|||
|
|
|||
|
_proto.getDefaultCfg = function getDefaultCfg() {
|
|||
|
var cfg = _Tooltip.prototype.getDefaultCfg.call(this);
|
|||
|
|
|||
|
return Util.mix({}, cfg, {
|
|||
|
/**
|
|||
|
* tooltip 容器模板
|
|||
|
* @type {String}
|
|||
|
*/
|
|||
|
containerTpl: ' <div class="' + CONTAINER_CLASS + '"> ' + '<div class="' + TITLE_CLASS + '"></div>' + '<ul class="' + LIST_CLASS + '"></ul>' + '</div>',
|
|||
|
|
|||
|
/**
|
|||
|
* tooltip 列表项模板
|
|||
|
* @type {String}
|
|||
|
*/
|
|||
|
itemTpl: "<li data-index={index}>\n <svg viewBox=\"0 0 " + MARKER_SIZE + " " + MARKER_SIZE + "\" class=\"" + MARKER_CLASS + "\"></svg>\n {name}<span class=\"" + VALUE_CLASS + "\">{value}</span></li>",
|
|||
|
|
|||
|
/**
|
|||
|
* tooltip html内容
|
|||
|
* @type {String}
|
|||
|
*/
|
|||
|
htmlContent: null,
|
|||
|
|
|||
|
/**
|
|||
|
* tooltip 内容跟随鼠标移动
|
|||
|
* @type {Boolean}
|
|||
|
*/
|
|||
|
follow: true,
|
|||
|
|
|||
|
/**
|
|||
|
* 是否允许鼠标停留在 tooltip 上,默认不允许
|
|||
|
* @type {Boolean}
|
|||
|
*/
|
|||
|
enterable: false
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
function HtmlTooltip(cfg) {
|
|||
|
var _this;
|
|||
|
|
|||
|
_this = _Tooltip.call(this, cfg) || this;
|
|||
|
Util.assign(_assertThisInitialized(_this), PositionMixin);
|
|||
|
Util.assign(_assertThisInitialized(_this), MarkerGroupMixin);
|
|||
|
var style = TooltipTheme;
|
|||
|
_this.style = mergeStyles(style, cfg);
|
|||
|
|
|||
|
_this._init_();
|
|||
|
|
|||
|
if (_this.get('items')) {
|
|||
|
_this.render();
|
|||
|
} // crosshair
|
|||
|
|
|||
|
|
|||
|
var crosshair = _this.get('crosshairs');
|
|||
|
|
|||
|
if (crosshair) {
|
|||
|
var plot = crosshair.type === 'rect' ? _this.get('backPlot') : _this.get('frontPlot');
|
|||
|
var crosshairGroup = new Crosshair(Util.mix({
|
|||
|
plot: plot,
|
|||
|
plotRange: _this.get('plotRange'),
|
|||
|
canvas: _this.get('canvas')
|
|||
|
}, _this.get('crosshairs')));
|
|||
|
crosshairGroup.hide();
|
|||
|
|
|||
|
_this.set('crosshairGroup', crosshairGroup);
|
|||
|
}
|
|||
|
|
|||
|
return _this;
|
|||
|
}
|
|||
|
|
|||
|
_proto._init_ = function _init_() {
|
|||
|
var self = this;
|
|||
|
var containerTpl = self.get('containerTpl');
|
|||
|
var outterNode = self.get('canvas').get('el').parentNode;
|
|||
|
var container;
|
|||
|
|
|||
|
if (!this.get('htmlContent')) {
|
|||
|
if (/^\#/.test(containerTpl)) {
|
|||
|
// 如果传入 dom 节点的 id
|
|||
|
var id = containerTpl.replace('#', '');
|
|||
|
container = document.getElementById(id);
|
|||
|
} else {
|
|||
|
container = DomUtil.createDom(containerTpl);
|
|||
|
DomUtil.modifyCSS(container, self.style[CONTAINER_CLASS]);
|
|||
|
outterNode.appendChild(container);
|
|||
|
outterNode.style.position = 'relative';
|
|||
|
}
|
|||
|
|
|||
|
self.set('container', container);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
_proto.render = function render() {
|
|||
|
var self = this;
|
|||
|
self.clear();
|
|||
|
|
|||
|
if (self.get('htmlContent')) {
|
|||
|
var outterNode = self.get('canvas').get('el').parentNode;
|
|||
|
|
|||
|
var container = self._getHtmlContent();
|
|||
|
|
|||
|
outterNode.appendChild(container);
|
|||
|
self.set('container', container);
|
|||
|
} else {
|
|||
|
self._renderTpl();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
_proto._renderTpl = function _renderTpl() {
|
|||
|
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');
|
|||
|
|
|||
|
if (titleDom && showTitle) {
|
|||
|
DomUtil.modifyCSS(titleDom, self.style[TITLE_CLASS]);
|
|||
|
titleDom.innerHTML = titleContent;
|
|||
|
}
|
|||
|
|
|||
|
if (listDom) {
|
|||
|
DomUtil.modifyCSS(listDom, self.style[LIST_CLASS]);
|
|||
|
Util.each(items, function (item, index) {
|
|||
|
listDom.appendChild(self._addItem(item, index));
|
|||
|
});
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
_proto.clear = function clear() {
|
|||
|
var container = this.get('container');
|
|||
|
|
|||
|
if (this.get('htmlContent')) {
|
|||
|
container && container.remove();
|
|||
|
} else {
|
|||
|
var titleDom = find(container, TITLE_CLASS);
|
|||
|
var listDom = find(container, LIST_CLASS);
|
|||
|
|
|||
|
if (titleDom) {
|
|||
|
titleDom.innerHTML = '';
|
|||
|
}
|
|||
|
|
|||
|
if (listDom) {
|
|||
|
listDom.innerHTML = '';
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
_proto.show = function show() {
|
|||
|
var container = this.get('container');
|
|||
|
|
|||
|
if (!container || this.destroyed) {
|
|||
|
// 防止容器不存在或者被销毁时报错
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
container.style.visibility = 'visible';
|
|||
|
container.style.display = 'block';
|
|||
|
var crosshairGroup = this.get('crosshairGroup');
|
|||
|
crosshairGroup && crosshairGroup.show();
|
|||
|
var markerGroup = this.get('markerGroup');
|
|||
|
markerGroup && markerGroup.show();
|
|||
|
|
|||
|
_Tooltip.prototype.show.call(this);
|
|||
|
|
|||
|
this.get('canvas').draw();
|
|||
|
};
|
|||
|
|
|||
|
_proto.hide = function hide() {
|
|||
|
var container = this.get('container'); // relative: https://github.com/antvis/g2/issues/1221
|
|||
|
|
|||
|
if (!container || this.destroyed) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
container.style.visibility = 'hidden';
|
|||
|
container.style.display = 'none';
|
|||
|
var crosshairGroup = this.get('crosshairGroup');
|
|||
|
crosshairGroup && crosshairGroup.hide();
|
|||
|
var markerGroup = this.get('markerGroup');
|
|||
|
markerGroup && markerGroup.hide();
|
|||
|
|
|||
|
_Tooltip.prototype.hide.call(this);
|
|||
|
|
|||
|
this.get('canvas').draw();
|
|||
|
};
|
|||
|
|
|||
|
_proto.destroy = function destroy() {
|
|||
|
var self = this;
|
|||
|
var container = self.get('container');
|
|||
|
var containerTpl = self.get('containerTpl');
|
|||
|
|
|||
|
if (container && !/^\#/.test(containerTpl)) {
|
|||
|
container.parentNode.removeChild(container);
|
|||
|
}
|
|||
|
|
|||
|
var crosshairGroup = this.get('crosshairGroup');
|
|||
|
crosshairGroup && crosshairGroup.destroy();
|
|||
|
var markerGroup = this.get('markerGroup');
|
|||
|
markerGroup && markerGroup.remove();
|
|||
|
|
|||
|
_Tooltip.prototype.destroy.call(this);
|
|||
|
};
|
|||
|
|
|||
|
_proto._getMarkerSvg = function _getMarkerSvg(item) {
|
|||
|
var marker = item.marker || {};
|
|||
|
var symbol = marker.activeSymbol || marker.symbol;
|
|||
|
var method;
|
|||
|
|
|||
|
if (Util.isFunction(symbol)) {
|
|||
|
method = symbol;
|
|||
|
} else if (Util.isString(symbol)) {
|
|||
|
method = Marker.Symbols[symbol];
|
|||
|
}
|
|||
|
|
|||
|
method = Util.isFunction(method) ? method : Marker.Symbols.circle;
|
|||
|
var pathArr = method(MARKER_SIZE / 2, MARKER_SIZE / 2, MARKER_SIZE / 2);
|
|||
|
var path = pathArr.reduce(function (res, arr) {
|
|||
|
return "" + res + arr[0] + arr.slice(1).join(',');
|
|||
|
}, '');
|
|||
|
return "<path d=\"" + path + "\" fill=\"" + (marker.fill || 'none') + "\" stroke=\"" + (marker.stroke || 'none') + "\" />";
|
|||
|
};
|
|||
|
|
|||
|
_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.style[LIST_ITEM_CLASS]);
|
|||
|
var markerDom = find(itemDOM, MARKER_CLASS);
|
|||
|
|
|||
|
if (markerDom) {
|
|||
|
DomUtil.modifyCSS(markerDom, _extends({}, this.style[MARKER_CLASS], {
|
|||
|
borderRadius: 'unset'
|
|||
|
}));
|
|||
|
|
|||
|
var markerPath = this._getMarkerSvg(item);
|
|||
|
|
|||
|
markerDom.innerHTML = markerPath;
|
|||
|
}
|
|||
|
|
|||
|
var valueDom = find(itemDOM, VALUE_CLASS);
|
|||
|
|
|||
|
if (valueDom) {
|
|||
|
DomUtil.modifyCSS(valueDom, this.style[VALUE_CLASS]);
|
|||
|
}
|
|||
|
|
|||
|
return itemDOM;
|
|||
|
};
|
|||
|
|
|||
|
_proto._getHtmlContent = function _getHtmlContent() {
|
|||
|
var htmlContent = this.get('htmlContent');
|
|||
|
var title = this.get('titleContent');
|
|||
|
var items = this.get('items');
|
|||
|
var htmlString = htmlContent(title, items);
|
|||
|
var ele = DomUtil.createDom(htmlString);
|
|||
|
return ele;
|
|||
|
};
|
|||
|
|
|||
|
_proto.setPosition = function setPosition(x, y, target) {
|
|||
|
var container = this.get('container');
|
|||
|
var outterNode = this.get('canvas').get('el');
|
|||
|
var viewWidth = DomUtil.getWidth(outterNode);
|
|||
|
var viewHeight = DomUtil.getHeight(outterNode);
|
|||
|
var containerWidth = container.clientWidth;
|
|||
|
var containerHeight = container.clientHeight;
|
|||
|
var endx = x;
|
|||
|
var endy = y;
|
|||
|
var position;
|
|||
|
var prePosition = this.get('prePosition') || {
|
|||
|
x: 0,
|
|||
|
y: 0
|
|||
|
}; // @2019-01-30 by blue.lb 由于display:none的元素获取clientWidth和clientHeight的值为0,这里强制显隐一下,其实直接在show和hide中去掉display设置最好,猜测为了更好的兼容浏览器
|
|||
|
|
|||
|
if (!containerWidth) {
|
|||
|
container.style.display = 'block';
|
|||
|
containerWidth = container.clientWidth;
|
|||
|
containerHeight = container.clientHeight;
|
|||
|
container.style.display = 'none';
|
|||
|
}
|
|||
|
|
|||
|
if (this.get('enterable')) {
|
|||
|
y = y - container.clientHeight / 2;
|
|||
|
position = [x, y];
|
|||
|
|
|||
|
if (prePosition && x - prePosition.x > 0) {
|
|||
|
// 留 1px 防止鼠标点击事件无法在画布上触发
|
|||
|
x -= container.clientWidth + 1;
|
|||
|
} else {
|
|||
|
x += 1;
|
|||
|
}
|
|||
|
} else if (this.get('position')) {
|
|||
|
// @2019-01-30 by blue.lb 这里应该是多余代码
|
|||
|
// const containerWidth = container.clientWidth;
|
|||
|
// const containerHeight = container.clientHeight;
|
|||
|
position = this._calcTooltipPosition(x, y, this.get('position'), containerWidth, containerHeight, target);
|
|||
|
x = position[0];
|
|||
|
y = position[1];
|
|||
|
} else {
|
|||
|
position = this._constraintPositionInBoundary(x, y, containerWidth, containerHeight, viewWidth, viewHeight);
|
|||
|
x = position[0];
|
|||
|
y = position[1];
|
|||
|
}
|
|||
|
|
|||
|
if (this.get('inPlot')) {
|
|||
|
// tooltip 必须限制在绘图区域内
|
|||
|
var plotRange = this.get('plotRange');
|
|||
|
position = this._constraintPositionInPlot(x, y, containerWidth, containerHeight, plotRange, this.get('enterable'));
|
|||
|
x = position[0];
|
|||
|
y = position[1];
|
|||
|
}
|
|||
|
|
|||
|
var markerItems = this.get('markerItems');
|
|||
|
|
|||
|
if (!Util.isEmpty(markerItems)) {
|
|||
|
endx = markerItems[0].x;
|
|||
|
endy = markerItems[0].y;
|
|||
|
}
|
|||
|
|
|||
|
this.set('prePosition', position); // 记录上次的位置
|
|||
|
|
|||
|
var follow = this.get('follow');
|
|||
|
|
|||
|
if (follow) {
|
|||
|
container.style.left = x + 'px';
|
|||
|
container.style.top = y + 'px';
|
|||
|
}
|
|||
|
|
|||
|
var crosshairGroup = this.get('crosshairGroup');
|
|||
|
|
|||
|
if (crosshairGroup) {
|
|||
|
var items = this.get('items');
|
|||
|
crosshairGroup.setPosition(endx, endy, items);
|
|||
|
}
|
|||
|
|
|||
|
_Tooltip.prototype.setPosition.call(this, x, y);
|
|||
|
};
|
|||
|
|
|||
|
return HtmlTooltip;
|
|||
|
}(Tooltip);
|
|||
|
|
|||
|
module.exports = HtmlTooltip;
|