UNPKG

16.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.findItemsFromViewRecurisive = exports.findItemsFromView = exports.getTooltipItems = exports.findDataByPoint = void 0;
4var tslib_1 = require("tslib");
5var util_1 = require("@antv/util");
6var constant_1 = require("../constant");
7var scale_1 = require("./scale");
8function snapEqual(v1, v2, scale) {
9 var value1 = scale.translate(v1);
10 var value2 = scale.translate(v2);
11 return util_1.isNumberEqual(value1, value2);
12}
13function getXValueByPoint(point, geometry) {
14 var coordinate = geometry.coordinate;
15 var xScale = geometry.getXScale();
16 var range = xScale.range;
17 var rangeMax = range[range.length - 1];
18 var rangeMin = range[0];
19 var invertPoint = coordinate.invert(point);
20 var xValue = invertPoint.x;
21 if (coordinate.isPolar && xValue > (1 + rangeMax) / 2) {
22 xValue = rangeMin; // 极坐标下,scale 的 range 被做过特殊处理
23 }
24 return xScale.translate(xScale.invert(xValue));
25}
26function filterYValue(data, point, geometry) {
27 var coordinate = geometry.coordinate;
28 var yScale = geometry.getYScale();
29 var yField = yScale.field;
30 var invertPoint = coordinate.invert(point);
31 var yValue = yScale.invert(invertPoint.y);
32 var result = util_1.find(data, function (obj) {
33 var originData = obj[constant_1.FIELD_ORIGIN];
34 return originData[yField][0] <= yValue && originData[yField][1] >= yValue;
35 });
36 return result || data[data.length - 1];
37}
38var getXDistance = util_1.memoize(function (scale) {
39 if (scale.isCategory) {
40 return 1;
41 }
42 var scaleValues = scale.values; // values 是无序的
43 var length = scaleValues.length;
44 var min = scale.translate(scaleValues[0]);
45 var max = min;
46 for (var index = 0; index < length; index++) {
47 var value = scaleValues[index];
48 // 时间类型需要 translate
49 var numericValue = scale.translate(value);
50 if (numericValue < min) {
51 min = numericValue;
52 }
53 if (numericValue > max) {
54 max = numericValue;
55 }
56 }
57 return (max - min) / (length - 1);
58});
59/**
60 * 获得 tooltip 的 title
61 * @param originData
62 * @param geometry
63 * @param title
64 */
65function getTooltipTitle(originData, geometry, title) {
66 var positionAttr = geometry.getAttribute('position');
67 var fields = positionAttr.getFields();
68 var scales = geometry.scales;
69 var titleField = util_1.isFunction(title) || !title ? fields[0] : title;
70 var titleScale = scales[titleField];
71 // 如果创建了该字段对应的 scale,则通过 scale.getText() 方式取值,因为用户可能对数据进行了格式化
72 // 如果没有对应的 scale,则从原始数据中取值,如果原始数据中仍不存在,则直接放回 title 值
73 var tooltipTitle = titleScale ? titleScale.getText(originData[titleField]) : originData[titleField] || titleField;
74 return util_1.isFunction(title) ? title(tooltipTitle, originData) : tooltipTitle;
75}
76function getAttributesForLegend(geometry) {
77 var attributes = util_1.values(geometry.attributes);
78 return util_1.filter(attributes, function (attribute) { return util_1.contains(constant_1.GROUP_ATTRS, attribute.type); });
79}
80function getTooltipValueScale(geometry) {
81 var attributes = getAttributesForLegend(geometry);
82 var scale;
83 for (var _i = 0, attributes_1 = attributes; _i < attributes_1.length; _i++) {
84 var attribute = attributes_1[_i];
85 var tmpScale = attribute.getScale(attribute.type);
86 if (tmpScale && tmpScale.isLinear) {
87 // 如果指定字段是非 position 的,同时是连续的
88 scale = tmpScale;
89 break;
90 }
91 }
92 var xScale = geometry.getXScale();
93 var yScale = geometry.getYScale();
94 return scale || yScale || xScale;
95}
96function getTooltipValue(originData, valueScale) {
97 var field = valueScale.field;
98 var value = originData[field];
99 if (util_1.isArray(value)) {
100 var texts = value.map(function (eachValue) {
101 return valueScale.getText(eachValue);
102 });
103 return texts.join('-');
104 }
105 return valueScale.getText(value);
106}
107// 根据原始数据获取 tooltip item 中 name 值
108function getTooltipName(originData, geometry) {
109 var nameScale;
110 var groupScales = geometry.getGroupScales();
111 if (groupScales.length) {
112 // 如果存在分组类型,取第一个分组类型
113 nameScale = groupScales[0];
114 }
115 if (nameScale) {
116 var field = nameScale.field;
117 return nameScale.getText(originData[field]);
118 }
119 var valueScale = getTooltipValueScale(geometry);
120 return scale_1.getName(valueScale);
121}
122/**
123 * @ignore
124 * Finds data from geometry by point
125 * @param point canvas point
126 * @param data an item of geometry.dataArray
127 * @param geometry
128 * @returns
129 */
130function findDataByPoint(point, data, geometry) {
131 if (data.length === 0) {
132 return null;
133 }
134 var geometryType = geometry.type;
135 var xScale = geometry.getXScale();
136 var yScale = geometry.getYScale();
137 var xField = xScale.field;
138 var yField = yScale.field;
139 var rst = null;
140 // 热力图采用最小逼近策略查找 point 击中的数据
141 if (geometryType === 'heatmap' || geometryType === 'point') {
142 // 将 point 画布坐标转换为原始数据值
143 var coordinate = geometry.coordinate;
144 var invertPoint = coordinate.invert(point); // 转换成归一化的数据
145 var x = xScale.invert(invertPoint.x); // 转换为原始值
146 var y = yScale.invert(invertPoint.y); // 转换为原始值
147 var min = Infinity;
148 for (var index = 0; index < data.length; index++) {
149 var obj = data[index];
150 var originData = obj[constant_1.FIELD_ORIGIN];
151 var range = Math.pow((originData[xField] - x), 2) + Math.pow((originData[yField] - y), 2);
152 if (range < min) {
153 min = range;
154 rst = obj;
155 }
156 }
157 return rst;
158 }
159 // 其他 Geometry 类型按照 x 字段数据进行查找
160 var first = data[0];
161 var last = data[data.length - 1];
162 var xValue = getXValueByPoint(point, geometry);
163 var firstXValue = first[constant_1.FIELD_ORIGIN][xField];
164 var firstYValue = first[constant_1.FIELD_ORIGIN][yField];
165 var lastXValue = last[constant_1.FIELD_ORIGIN][xField];
166 var isYArray = yScale.isLinear && util_1.isArray(firstYValue); // 考虑 x 维度相同,y 是数组区间的情况
167 // 如果 x 的值是数组
168 if (util_1.isArray(firstXValue)) {
169 for (var index = 0; index < data.length; index++) {
170 var record = data[index];
171 var originData = record[constant_1.FIELD_ORIGIN];
172 // xValue 在 originData[xField] 的数值区间内
173 if (xScale.translate(originData[xField][0]) <= xValue && xScale.translate(originData[xField][1]) >= xValue) {
174 if (isYArray) {
175 // 层叠直方图场景,x 和 y 都是数组区间
176 if (!util_1.isArray(rst)) {
177 rst = [];
178 }
179 rst.push(record);
180 }
181 else {
182 rst = record;
183 break;
184 }
185 }
186 }
187 if (util_1.isArray(rst)) {
188 rst = filterYValue(rst, point, geometry);
189 }
190 }
191 else {
192 var next = void 0;
193 if (!xScale.isLinear && xScale.type !== 'timeCat') {
194 // x 轴对应的数据为非线性以及非时间类型的数据采用遍历查找
195 for (var index = 0; index < data.length; index++) {
196 var record = data[index];
197 var originData = record[constant_1.FIELD_ORIGIN];
198 if (snapEqual(originData[xField], xValue, xScale)) {
199 if (isYArray) {
200 if (!util_1.isArray(rst)) {
201 rst = [];
202 }
203 rst.push(record);
204 }
205 else {
206 rst = record;
207 break;
208 }
209 }
210 else if (xScale.translate(originData[xField]) <= xValue) {
211 last = record;
212 next = data[index + 1];
213 }
214 }
215 if (util_1.isArray(rst)) {
216 rst = filterYValue(rst, point, geometry);
217 }
218 }
219 else {
220 // x 轴对应的数据为线性以及时间类型,进行二分查找,性能更好
221 if ((xValue > xScale.translate(lastXValue) || xValue < xScale.translate(firstXValue)) &&
222 (xValue > xScale.max || xValue < xScale.min)) {
223 // 不在数据范围内
224 return null;
225 }
226 var firstIdx = 0;
227 var lastIdx = data.length - 1;
228 var middleIdx = void 0;
229 while (firstIdx <= lastIdx) {
230 middleIdx = Math.floor((firstIdx + lastIdx) / 2);
231 var item = data[middleIdx][constant_1.FIELD_ORIGIN][xField];
232 if (snapEqual(item, xValue, xScale)) {
233 return data[middleIdx];
234 }
235 if (xScale.translate(item) <= xScale.translate(xValue)) {
236 firstIdx = middleIdx + 1;
237 last = data[middleIdx];
238 next = data[middleIdx + 1];
239 }
240 else {
241 if (lastIdx === 0) {
242 last = data[0];
243 }
244 lastIdx = middleIdx - 1;
245 }
246 }
247 }
248 if (last && next) {
249 // 计算最逼近的
250 if (Math.abs(xScale.translate(last[constant_1.FIELD_ORIGIN][xField]) - xValue) >
251 Math.abs(xScale.translate(next[constant_1.FIELD_ORIGIN][xField]) - xValue)) {
252 last = next;
253 }
254 }
255 }
256 var distance = getXDistance(geometry.getXScale()); // 每个分类间的平均间距
257 if (!rst && Math.abs(xScale.translate(last[constant_1.FIELD_ORIGIN][xField]) - xValue) <= distance / 2) {
258 rst = last;
259 }
260 return rst;
261}
262exports.findDataByPoint = findDataByPoint;
263/**
264 * @ignore
265 * Gets tooltip items
266 * @param data
267 * @param geometry
268 * @param [title]
269 * @returns
270 */
271function getTooltipItems(data, geometry, title, showNil) {
272 if (title === void 0) { title = ''; }
273 if (showNil === void 0) { showNil = false; }
274 var originData = data[constant_1.FIELD_ORIGIN];
275 var tooltipTitle = getTooltipTitle(originData, geometry, title);
276 var tooltipOption = geometry.tooltipOption;
277 var defaultColor = geometry.theme.defaultColor;
278 var items = [];
279 var name;
280 var value;
281 function addItem(itemName, itemValue) {
282 if (showNil || (!util_1.isNil(itemValue) && itemValue !== '')) {
283 // 值为 null的时候,忽视
284 var item = {
285 title: tooltipTitle,
286 data: originData,
287 mappingData: data,
288 name: itemName,
289 value: itemValue,
290 color: data.color || defaultColor,
291 marker: true,
292 };
293 items.push(item);
294 }
295 }
296 if (util_1.isObject(tooltipOption)) {
297 var fields = tooltipOption.fields, callback = tooltipOption.callback;
298 if (callback) {
299 // 用户定义了回调函数
300 var callbackParams = fields.map(function (field) {
301 return data[constant_1.FIELD_ORIGIN][field];
302 });
303 var cfg = callback.apply(void 0, callbackParams);
304 var itemCfg = tslib_1.__assign({ data: data[constant_1.FIELD_ORIGIN], mappingData: data, title: tooltipTitle, color: data.color || defaultColor, marker: true }, cfg);
305 items.push(itemCfg);
306 }
307 else {
308 var scales = geometry.scales;
309 for (var _i = 0, fields_1 = fields; _i < fields_1.length; _i++) {
310 var field = fields_1[_i];
311 if (!util_1.isNil(originData[field])) {
312 // 字段数据为null, undefined 时不显示
313 var scale = scales[field];
314 name = scale_1.getName(scale);
315 value = scale.getText(originData[field]);
316 addItem(name, value);
317 }
318 }
319 }
320 }
321 else {
322 var valueScale = getTooltipValueScale(geometry);
323 // 字段数据为null ,undefined时不显示
324 value = getTooltipValue(originData, valueScale);
325 name = getTooltipName(originData, geometry);
326 addItem(name, value);
327 }
328 return items;
329}
330exports.getTooltipItems = getTooltipItems;
331function getTooltipItemsByFindData(geometry, point, title, tooltipCfg) {
332 var showNil = tooltipCfg.showNil;
333 var result = [];
334 var dataArray = geometry.dataArray;
335 if (!util_1.isEmpty(dataArray)) {
336 geometry.sort(dataArray); // 先进行排序,便于 tooltip 查找
337 for (var _i = 0, dataArray_1 = dataArray; _i < dataArray_1.length; _i++) {
338 var data = dataArray_1[_i];
339 var record = findDataByPoint(point, data, geometry);
340 if (record) {
341 var elementId = geometry.getElementId(record);
342 var element = geometry.elementsMap[elementId];
343 if (geometry.type === 'heatmap' || element.visible) {
344 // Heatmap 没有 Element
345 // 如果图形元素隐藏了,怎不再 tooltip 上展示相关数据
346 var items = getTooltipItems(record, geometry, title, showNil);
347 if (items.length) {
348 result.push(items);
349 }
350 }
351 }
352 }
353 }
354 return result;
355}
356function getTooltipItemsByHitShape(geometry, point, title, tooltipCfg) {
357 var showNil = tooltipCfg.showNil;
358 var result = [];
359 var container = geometry.container;
360 var shape = container.getShape(point.x, point.y);
361 if (shape && shape.get('visible') && shape.get('origin')) {
362 var mappingData = shape.get('origin').mappingData;
363 var items = getTooltipItems(mappingData, geometry, title, showNil);
364 if (items.length) {
365 result.push(items);
366 }
367 }
368 return result;
369}
370/**
371 * 不进行递归查找
372 */
373function findItemsFromView(view, point, tooltipCfg) {
374 var result = [];
375 // 先从 view 本身查找
376 var geometries = view.geometries;
377 var shared = tooltipCfg.shared, title = tooltipCfg.title, reversed = tooltipCfg.reversed;
378 for (var _i = 0, geometries_1 = geometries; _i < geometries_1.length; _i++) {
379 var geometry = geometries_1[_i];
380 if (geometry.visible && geometry.tooltipOption !== false) {
381 // geometry 可见同时未关闭 tooltip
382 var geometryType = geometry.type;
383 var tooltipItems = void 0;
384 if (['point', 'edge', 'polygon'].includes(geometryType)) {
385 // 始终通过图形拾取
386 tooltipItems = getTooltipItemsByHitShape(geometry, point, title, tooltipCfg);
387 }
388 else if (['area', 'line', 'path', 'heatmap'].includes(geometryType)) {
389 // 如果是 'area', 'line', 'path',始终通过数据查找方法查找 tooltip
390 tooltipItems = getTooltipItemsByFindData(geometry, point, title, tooltipCfg);
391 }
392 else {
393 if (shared !== false) {
394 tooltipItems = getTooltipItemsByFindData(geometry, point, title, tooltipCfg);
395 }
396 else {
397 tooltipItems = getTooltipItemsByHitShape(geometry, point, title, tooltipCfg);
398 }
399 }
400 if (tooltipItems.length) {
401 if (reversed) {
402 tooltipItems.reverse();
403 }
404 // geometry 有可能会有多个 item,因为用户可以设置 geometry.tooltip('x*y*z')
405 result.push(tooltipItems);
406 }
407 }
408 }
409 return result;
410}
411exports.findItemsFromView = findItemsFromView;
412function findItemsFromViewRecurisive(view, point, tooltipCfg) {
413 var result = findItemsFromView(view, point, tooltipCfg);
414 // 递归查找,并合并结果
415 for (var _i = 0, _a = view.views; _i < _a.length; _i++) {
416 var childView = _a[_i];
417 result = result.concat(findItemsFromView(childView, point, tooltipCfg));
418 }
419 return result;
420}
421exports.findItemsFromViewRecurisive = findItemsFromViewRecurisive;
422//# sourceMappingURL=tooltip.js.map
\No newline at end of file