/** * @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(); // 鏋佸潗鏍囦笅锛宻cale 鐨� 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 缁村害鐩稿悓锛寉 鏄暟缁勫尯闂寸殑鎯呭喌 // 濡傛灉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; }, /** * 鑾峰彇鐐瑰搴攖ooltip鐨勪俊鎭� * @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])) { // 瀛楁鏁版嵁涓簄ull ,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])) { // 瀛楁鏁版嵁涓簄ull ,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;