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; |