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

513 lines
14 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.

/**
* @fileOverview The tooltip handler
* @author sima.zhang
*/
var Util = require('../../util');
var _require = require('../../global'),
defaultColor = _require.defaultColor;
var FIELD_ORIGIN = '_origin';
function getScaleName(scale) {
return scale.alias || scale.field;
}
var TooltipMixin = {
_getIntervalSize: function _getIntervalSize(obj) {
var size = null;
var type = this.get('type');
var coord = this.get('coord');
if (coord.isRect && (type === 'interval' || type === 'schema')) {
size = this.getSize(obj[FIELD_ORIGIN]); // 如果字段发生了映射,宽度计算就会报错
var dim = coord.isTransposed ? 'y' : 'x';
if (Util.isArray(obj[dim])) {
var width = Math.abs(obj[dim][1] - obj[dim][0]);
size = size < width ? null : size; // 直方图计算错误
}
}
return size;
},
_snapEqual: function _snapEqual(v1, v2, scale) {
var equals;
v1 = scale.translate(v1);
v2 = scale.translate(v2);
if (scale.isCategory) {
equals = v1 === v2;
} else {
equals = Util.snapEqual(v1, v2);
}
return equals;
},
_getScaleValueByPoint: function _getScaleValueByPoint(point) {
var result = 0;
var coord = this.get('coord');
var xScale = this.getXScale();
var invertPoint = coord.invert(point);
var xValue = invertPoint.x;
if (this.isInCircle() && xValue > (1 + xScale.rangeMax()) / 2) {
xValue = xScale.rangeMin(); // 极坐标下scale 的 range 被做过特殊处理 see view.js#L88
}
result = xScale.invert(xValue);
if (xScale.isCategory) {
result = xScale.translate(result); // 防止分类类型
}
return result;
},
_getOriginByPoint: function _getOriginByPoint(point) {
var xScale = this.getXScale();
var yScale = this.getYScale();
var xField = xScale.field;
var yField = yScale.field;
var coord = this.get('coord');
var invertPoint = coord.invert(point);
var xValue = xScale.invert(invertPoint.x);
var yValue = yScale.invert(invertPoint.y);
var result = {};
result[xField] = xValue;
result[yField] = yValue;
return result;
},
_getScale: function _getScale(field) {
var self = this;
var scales = self.get('scales');
var rst = null;
Util.each(scales, function (scale) {
if (scale.field === field) {
rst = scale;
return false;
}
});
return rst;
},
// 获取值对应的度量
_getTipValueScale: function _getTipValueScale() {
var attrs = this.getAttrsForLegend();
var scale;
Util.each(attrs, function (attr) {
var tmpScale = attr.getScale(attr.type);
if (tmpScale.isLinear) {
// 如果指定字段是非position的同时是连续的
scale = tmpScale;
return false;
}
});
var xScale = this.getXScale();
var yScale = this.getYScale();
if (!scale && yScale && yScale.field === '..y') {
return xScale;
}
return scale || yScale || xScale;
},
_getTipTitleScale: function _getTipTitleScale(titleField) {
var self = this;
if (titleField) {
return self._getScale(titleField);
}
var position = self.getAttr('position');
var fields = position.getFields();
var tmpField;
Util.each(fields, function (field) {
if (!field.includes('..')) {
tmpField = field;
return false;
}
});
return self._getScale(tmpField);
},
_filterValue: function _filterValue(arr, point) {
var coord = this.get('coord');
var yScale = this.getYScale();
var yField = yScale.field;
var invertPoint = coord.invert(point);
var yValue = invertPoint.y;
yValue = yScale.invert(yValue);
var rst = arr[arr.length - 1];
Util.each(arr, function (obj) {
var origin = obj[FIELD_ORIGIN];
if (origin[yField][0] <= yValue && origin[yField][1] >= yValue) {
rst = obj;
return false;
}
});
return rst;
},
getXDistance: function getXDistance() {
var self = this;
var distance = self.get('xDistance');
if (!distance) {
var xScale = self.getXScale();
if (xScale.isCategory) {
distance = 1;
} else {
var values = xScale.values; // values 是无序的
var min = xScale.translate(values[0]);
var max = min;
Util.each(values, function (value) {
// 时间类型需要 translate
value = xScale.translate(value);
if (value < min) {
min = value;
}
if (value > max) {
max = value;
}
});
var length = values.length; // 应该是除以 length - 1
distance = (max - min) / (length - 1);
}
self.set('xDistance', distance);
}
return distance;
},
findPoint: function findPoint(point, dataArray) {
var self = this;
var type = self.get('type');
var xScale = self.getXScale();
var yScale = self.getYScale();
var xField = xScale.field;
var yField = yScale.field;
var rst = null;
if (Util.indexOf(['heatmap', 'point'], type) > -1) {
var coord = self.get('coord');
var invertPoint = coord.invert(point);
var xValue = xScale.invert(invertPoint.x);
var yValue = yScale.invert(invertPoint.y);
var min = Infinity;
Util.each(dataArray, function (obj) {
var distance = Math.pow(obj[FIELD_ORIGIN][xField] - xValue, 2) + Math.pow(obj[FIELD_ORIGIN][yField] - yValue, 2);
if (distance < min) {
min = distance;
rst = obj;
}
});
return rst;
}
var first = dataArray[0];
var last = dataArray[dataArray.length - 1];
if (!first) {
return rst;
}
var value = self._getScaleValueByPoint(point); // 根据该点获得对应度量后数据的值
var firstXValue = first[FIELD_ORIGIN][xField];
var firstYValue = first[FIELD_ORIGIN][yField];
var lastXValue = last[FIELD_ORIGIN][xField];
var isYRange = yScale.isLinear && Util.isArray(firstYValue); // 考虑 x 维度相同y 是数组区间的情况
// 如果x的值是数组
if (Util.isArray(firstXValue)) {
Util.each(dataArray, function (record) {
var origin = record[FIELD_ORIGIN];
if (xScale.translate(origin[xField][0]) <= value && xScale.translate(origin[xField][1]) >= value) {
if (isYRange) {
if (!Util.isArray(rst)) {
rst = [];
}
rst.push(record);
} else {
rst = record;
return false;
}
}
});
if (Util.isArray(rst)) {
rst = this._filterValue(rst, point);
}
} else {
var next;
if (!xScale.isLinear && xScale.type !== 'timeCat') {
Util.each(dataArray, function (record, index) {
var origin = record[FIELD_ORIGIN];
if (self._snapEqual(origin[xField], value, xScale)) {
if (isYRange) {
if (!Util.isArray(rst)) {
rst = [];
}
rst.push(record);
} else {
rst = record;
return false;
}
} else if (xScale.translate(origin[xField]) <= value) {
last = record;
next = dataArray[index + 1];
}
});
if (Util.isArray(rst)) {
rst = this._filterValue(rst, point);
}
} else {
if ((value > xScale.translate(lastXValue) || value < xScale.translate(firstXValue)) && (value > xScale.max || value < xScale.min)) {
return null;
}
var firstIdx = 0;
var lastIdx = dataArray.length - 1;
var middleIdx;
while (firstIdx <= lastIdx) {
middleIdx = Math.floor((firstIdx + lastIdx) / 2);
var item = dataArray[middleIdx][FIELD_ORIGIN][xField];
if (self._snapEqual(item, value, xScale)) {
return dataArray[middleIdx];
}
if (xScale.translate(item) <= xScale.translate(value)) {
firstIdx = middleIdx + 1;
last = dataArray[middleIdx];
next = dataArray[middleIdx + 1];
} else {
if (lastIdx === 0) {
last = dataArray[0];
}
lastIdx = middleIdx - 1;
}
}
}
if (last && next) {
// 计算最逼近的
if (Math.abs(xScale.translate(last[FIELD_ORIGIN][xField]) - value) > Math.abs(xScale.translate(next[FIELD_ORIGIN][xField]) - value)) {
last = next;
}
}
}
var distance = self.getXDistance(); // 每个分类间的平均间距
if (!rst && Math.abs(xScale.translate(last[FIELD_ORIGIN][xField]) - value) <= distance / 2) {
rst = last;
}
return rst;
},
/**
* @protected
* 获取tooltip的标题
* @param {Object} origin 点的原始信息
* @param {String} titleField 标题的字段
* @return {String} 提示信息的标题
*/
getTipTitle: function getTipTitle(origin, titleField) {
var tipTitle = '';
var titleScale = this._getTipTitleScale(titleField);
if (titleScale) {
var value = origin[titleScale.field];
tipTitle = titleScale.getText(value);
} else if (this.get('type') === 'heatmap') {
// 热力图在不存在 title 的时候特殊处理
var xScale = this.getXScale();
var yScale = this.getYScale();
var xValue = xScale.getText(origin[xScale.field]);
var yValue = yScale.getText(origin[yScale.field]);
tipTitle = '( ' + xValue + ', ' + yValue + ' )';
}
return tipTitle;
},
getTipValue: function getTipValue(origin, valueScale) {
var value;
var field = valueScale.field;
var key = origin.key;
value = origin[field];
if (Util.isArray(value)) {
var tmp = [];
Util.each(value, function (sub) {
tmp.push(valueScale.getText(sub));
});
value = tmp.join('-');
} else {
value = valueScale.getText(value, key);
}
return value;
},
/**
* @protected
* 获取tooltip的名称
* @param {Object} origin 点的原始信息
* @return {String} 提示信息的名称
*/
getTipName: function getTipName(origin) {
var name;
var nameScale;
var groupScales = this._getGroupScales();
if (groupScales.length) {
// 如果存在分组类型,取第一个分组类型
Util.each(groupScales, function (scale) {
nameScale = scale;
return false;
});
}
if (nameScale) {
var field = nameScale.field;
name = nameScale.getText(origin[field]);
} else {
var valueScale = this._getTipValueScale();
name = getScaleName(valueScale);
}
return name;
},
/**
* 获取点对应tooltip的信息
* @protected
* @param {Object} point 原始的数据记录
* @param {String} titleField tooltipTitle 配置信息
* @return {Array} 一条或者多条记录
*/
getTipItems: function getTipItems(point, titleField) {
var self = this;
var origin = point[FIELD_ORIGIN];
var tipTitle = self.getTipTitle(origin, titleField);
var tooltipCfg = self.get('tooltipCfg');
var items = [];
var name;
var value;
function addItem(itemName, itemValue, cfg) {
if (!Util.isNil(itemValue) && itemValue !== '') {
// 值为null的时候忽视
var item = {
title: tipTitle,
point: point,
name: itemName || tipTitle,
value: itemValue,
color: point.color || defaultColor,
marker: true
};
item.size = self._getIntervalSize(point);
items.push(Util.mix({}, item, cfg));
}
}
if (tooltipCfg) {
var fields = tooltipCfg.fields;
var cfg = tooltipCfg.cfg;
var callbackParams = [];
Util.each(fields, function (field) {
callbackParams.push(origin[field]);
});
if (cfg) {
// 存在回调函数
if (Util.isFunction(cfg)) {
cfg = cfg.apply(null, callbackParams);
}
var itemCfg = Util.mix({}, {
point: point,
title: tipTitle,
color: point.color || defaultColor,
marker: true // 默认展示 marker
}, cfg);
itemCfg.size = self._getIntervalSize(point);
items.push(itemCfg);
} else {
Util.each(fields, function (field) {
if (!Util.isNil(origin[field])) {
// 字段数据为null ,undefined时不显示
var scale = self._getScale(field);
name = getScaleName(scale);
value = scale.getText(origin[field]);
addItem(name, value);
}
});
}
} else {
var valueScale = self._getTipValueScale();
if (!Util.isNil(origin[valueScale.field])) {
// 字段数据为null ,undefined时不显示
value = self.getTipValue(origin, valueScale);
name = self.getTipName(origin);
addItem(name, value);
}
}
return items;
},
isShareTooltip: function isShareTooltip() {
var shareTooltip = this.get('shareTooltip');
var type = this.get('type');
var view = this.get('view');
var options;
if (view.get('parent')) {
options = view.get('parent').get('options');
} else {
options = view.get('options');
}
if (type === 'interval') {
var coord = this.get('coord');
var coordType = coord.type;
if (coordType === 'theta' || coordType === 'polar' && coord.isTransposed) {
shareTooltip = false;
}
} else if (!this.getYScale() || Util.inArray(['contour', 'point', 'polygon', 'edge'], type)) {
shareTooltip = false;
}
if (options.tooltip && Util.isBoolean(options.tooltip.shared)) {
// 以用户设置的为准
shareTooltip = options.tooltip.shared;
}
return shareTooltip;
}
};
module.exports = TooltipMixin;