UNPKG

21.7 kBJavaScriptView Raw
1import { __assign, __extends, __rest } from "tslib";
2import { isFunction, each, upperFirst, mix, groupToMap, isObject, flatten, isNull, find } from '@antv/util';
3import Selection from './selection';
4import { Dodge, Jitter, Stack, Symmetric } from '../../deps/f2-adjust/src';
5import { toTimeStamp } from '../../util/index';
6import AttrController from '../../controller/attr';
7import { isEqual } from '@antv/f-engine';
8var AdjustMap = {
9 Stack: Stack,
10 Dodge: Dodge,
11 Jitter: Jitter,
12 Symmetric: Symmetric
13};
14// 保留原始数据的字段
15var FIELD_ORIGIN = 'origin';
16var Geometry = /** @class */function (_super) {
17 __extends(Geometry, _super);
18 function Geometry(props, context) {
19 var _this = _super.call(this, props, context) || this;
20 _this.isGeometry = true;
21 // x 轴居中
22 _this.justifyContent = false;
23 // y 轴是否从0开始
24 _this.startOnZero = false;
25 // 是否连接空值
26 _this.connectNulls = false;
27 // 是否需要排序
28 _this.sortable = false;
29 mix(_this, _this.getDefaultCfg());
30 var chart = props.chart,
31 coord = props.coord;
32 var attrsRange = _this._getThemeAttrsRange();
33 _this.attrController = new AttrController(chart.scale, attrsRange);
34 var _a = _this,
35 attrController = _a.attrController,
36 justifyContent = _a.justifyContent;
37 var attrOptions = attrController.getAttrOptions(props, !coord.isCyclic() || justifyContent);
38 attrController.create(attrOptions);
39 return _this;
40 }
41 Geometry.prototype.getDefaultCfg = function () {
42 return {};
43 };
44 Geometry.prototype.willReceiveProps = function (nextProps) {
45 var _a = this,
46 lastProps = _a.props,
47 attrController = _a.attrController,
48 justifyContent = _a.justifyContent;
49 var nextData = nextProps.data,
50 nextAdjust = nextProps.adjust,
51 coord = nextProps.coord,
52 selection = nextProps.selection;
53 var lastData = lastProps.data,
54 lastAdjust = lastProps.adjust,
55 lastSelection = lastProps.selection;
56 var justifyContentCenter = !coord.isCyclic() || justifyContent;
57 var lastAttrOptions = attrController.getAttrOptions(lastProps, justifyContentCenter);
58 attrController.attrsRange = this._getThemeAttrsRange();
59 var nextAttrOptions = attrController.getAttrOptions(nextProps, justifyContentCenter);
60 if (!isEqual(nextAttrOptions, lastAttrOptions)) {
61 attrController.update(nextAttrOptions);
62 this.dataRecords = null;
63 }
64 // 重新处理数据
65 if (nextData !== lastData) {
66 this.dataRecords = null;
67 }
68 // 重新处理数据
69 if (nextAdjust !== lastAdjust) {
70 this.dataRecords = null;
71 }
72 // selection 发生变化
73 if (!isEqual(selection, lastSelection)) {
74 _super.prototype.willReceiveProps.call(this, nextProps);
75 }
76 };
77 Geometry.prototype.willMount = function () {
78 this._createAttrs();
79 if (!this.dataRecords) {
80 this._processData();
81 }
82 };
83 Geometry.prototype.willUpdate = function () {
84 this._createAttrs();
85 if (!this.dataRecords) {
86 this._processData();
87 } else {
88 this._readjustData(this.dataRecords);
89 }
90 };
91 Geometry.prototype.didMount = function () {
92 this._initEvent();
93 _super.prototype.didMount.call(this);
94 // 更新 attrController
95 this.attrController.attrsRange = this._getThemeAttrsRange();
96 };
97 Geometry.prototype._initEvent = function () {
98 var _this = this;
99 var props = this.props;
100 var chart = props.chart;
101 ['onPressStart', 'onPress', 'onPressEnd', 'onPan', 'onPanStart', 'onPanEnd'].forEach(function (eventName) {
102 if (props[eventName]) {
103 chart.on(eventName.substr(2).toLowerCase(), function (ev) {
104 ev.geometry = _this;
105 props[eventName](ev);
106 });
107 }
108 });
109 };
110 Geometry.prototype._createAttrs = function () {
111 var attrController = this.attrController;
112 attrController.attrs = {};
113 this.attrs = attrController.getAttrs();
114 };
115 Geometry.prototype._getThemeAttrsRange = function () {
116 var _a = this,
117 context = _a.context,
118 props = _a.props,
119 geomType = _a.geomType;
120 var coord = props.coord;
121 var theme = context.theme;
122 var colors = theme.colors,
123 sizes = theme.sizes,
124 shapes = theme.shapes;
125 return {
126 x: coord.x,
127 y: coord.y,
128 color: colors,
129 size: sizes,
130 shape: shapes[geomType]
131 };
132 };
133 Geometry.prototype._createAdjust = function () {
134 var _a = this,
135 attrs = _a.attrs,
136 props = _a.props;
137 var adjust = props.adjust;
138 if (!adjust) {
139 return null;
140 }
141 var adjustCfg = typeof adjust === 'string' ? {
142 type: adjust
143 } : adjust;
144 var adjustType = upperFirst(adjustCfg.type);
145 var AdjustConstructor = AdjustMap[adjustType];
146 if (!AdjustConstructor) {
147 throw new Error('not support such adjust : ' + adjust);
148 }
149 if (adjustType === 'Dodge') {
150 // @ts-ignore
151 adjustCfg.adjustNames = ['x'];
152 }
153 var x = attrs.x,
154 y = attrs.y;
155 // @ts-ignore
156 adjustCfg.xField = x.field;
157 // @ts-ignore
158 adjustCfg.yField = y.field;
159 var adjustInstance = new AdjustConstructor(adjustCfg);
160 this.adjust = {
161 type: adjustCfg.type,
162 adjust: adjustInstance
163 };
164 return this.adjust;
165 };
166 Geometry.prototype._adjustScales = function () {
167 var _a = this,
168 attrs = _a.attrs,
169 props = _a.props,
170 defaultStartOnZero = _a.startOnZero;
171 var chart = props.chart,
172 _b = props.startOnZero,
173 startOnZero = _b === void 0 ? defaultStartOnZero : _b,
174 coord = props.coord,
175 adjust = props.adjust;
176 var isPolar = coord.isPolar,
177 transposed = coord.transposed;
178 var y = attrs.y;
179 var yField = y.field;
180 // 如果从 0 开始,只调整 y 轴 scale
181 if (startOnZero) {
182 var y_1 = attrs.y;
183 chart.scale.adjustStartZero(y_1.scale);
184 }
185 // 饼图的scale调整,关闭nice
186 if (isPolar && transposed && (adjust === 'stack' || (adjust === null || adjust === void 0 ? void 0 : adjust.type) === 'stack')) {
187 var y_2 = attrs.y;
188 chart.scale.adjustPieScale(y_2.scale);
189 }
190 if (adjust === 'stack' || (adjust === null || adjust === void 0 ? void 0 : adjust.type) === 'stack') {
191 this._updateStackRange(yField, y.scale, this.dataArray);
192 }
193 };
194 Geometry.prototype._groupData = function (data) {
195 var attrController = this.attrController;
196 var groupScales = attrController.getGroupScales();
197 if (!groupScales.length) {
198 return [{
199 children: data
200 }];
201 }
202 var names = [];
203 groupScales.forEach(function (scale) {
204 var field = scale.field;
205 names.push(field);
206 });
207 var groups = groupToMap(data, names);
208 var records = [];
209 for (var key in groups) {
210 records.push({
211 key: key.replace(/^_/, ''),
212 children: groups[key]
213 });
214 }
215 return records;
216 };
217 Geometry.prototype._saveOrigin = function (originData) {
218 var _a;
219 var len = originData.length;
220 var data = new Array(len);
221 for (var i = 0; i < len; i++) {
222 var record = originData[i];
223 data[i] = __assign(__assign({}, record), (_a = {}, _a[FIELD_ORIGIN] = record, _a));
224 }
225 return data;
226 };
227 Geometry.prototype._numberic = function (data) {
228 var attrs = this.attrs;
229 var scales = [attrs.x.scale, attrs.y.scale];
230 for (var j = 0, len = data.length; j < len; j++) {
231 var obj = data[j];
232 var count = scales.length;
233 for (var i = 0; i < count; i++) {
234 var scale = scales[i];
235 if (scale.isCategory) {
236 var field = scale.field;
237 var value = scale.translate(obj.origin[field]);
238 obj[field] = value;
239 }
240 }
241 }
242 };
243 Geometry.prototype._adjustData = function (records) {
244 var adjust = this.adjust;
245 // groupedArray 是二维数组
246 var groupedArray = records.map(function (record) {
247 return record.children;
248 });
249 if (!adjust) {
250 return groupedArray;
251 }
252 var attrs = this.attrs;
253 var scales = [attrs.x.scale, attrs.y.scale];
254 for (var i = 0, len = groupedArray.length; i < len; i++) {
255 var records_1 = groupedArray[i];
256 for (var j = 0, len_1 = records_1.length; j < len_1; j++) {
257 var record = records_1[j];
258 var count = scales.length;
259 for (var i_1 = 0; i_1 < count; i_1++) {
260 var scale = scales[i_1];
261 var field = scale.field;
262 record[field] = record.origin[field];
263 }
264 }
265 }
266 if (adjust.type === 'dodge') {
267 for (var i = 0, len = groupedArray.length; i < len; i++) {
268 // 如果是dodge, 需要处理数字再处理
269 this._numberic(groupedArray[i]);
270 }
271 }
272 var adjustData = adjust.adjust.process(groupedArray);
273 // process 返回的是新数组,所以要修改 records
274 records.forEach(function (record, index) {
275 record.children = adjustData[index];
276 });
277 return adjustData;
278 };
279 Geometry.prototype._updateStackRange = function (field, scale, dataArray) {
280 var flattenArray = flatten(dataArray);
281 var min = Infinity;
282 var max = -Infinity;
283 for (var i = 0, len = flattenArray.length; i < len; i++) {
284 var obj = flattenArray[i];
285 var tmpMin = Math.min.apply(null, obj[field]);
286 var tmpMax = Math.max.apply(null, obj[field]);
287 if (tmpMin < min) {
288 min = tmpMin;
289 }
290 if (tmpMax > max) {
291 max = tmpMax;
292 }
293 }
294 if (min !== scale.min || max !== scale.max) {
295 scale.change({
296 min: min,
297 max: max
298 });
299 }
300 };
301 Geometry.prototype._processData = function () {
302 var props = this.props;
303 var originData = props.data;
304 var data = this._saveOrigin(originData);
305 // 根据分类度量进行数据分组
306 var records = this._groupData(data);
307 this._createAdjust();
308 // 根据adjust分组
309 var dataArray = this._adjustData(records);
310 this.dataArray = dataArray;
311 // scale适配调整,主要是调整 y 轴是否从 0 开始 以及 饼图
312 this._adjustScales();
313 // 数据排序(非必须)
314 if (this.sortable) {
315 this._sortData(records);
316 }
317 this.dataRecords = records;
318 };
319 Geometry.prototype._readjustData = function (records) {
320 var adjust = this.adjust;
321 if (!adjust) return;
322 // 根据adjust分组
323 var dataArray = this._adjustData(records);
324 this.dataArray = dataArray;
325 };
326 Geometry.prototype._sortData = function (records) {
327 var xScale = this.getXScale();
328 var field = xScale.field,
329 type = xScale.type;
330 if (type !== 'identity' && xScale.values.length > 1) {
331 each(records, function (_a) {
332 var children = _a.children;
333 children.sort(function (record1, record2) {
334 if (type === 'timeCat') {
335 return toTimeStamp(record1[FIELD_ORIGIN][field]) - toTimeStamp(record2[FIELD_ORIGIN][field]);
336 }
337 var normalized1 = xScale.translate(record1[FIELD_ORIGIN][field]);
338 var normalized2 = xScale.translate(record2[FIELD_ORIGIN][field]);
339 if (isNaN(normalized1)) {
340 return 1;
341 }
342 if (isNaN(normalized2)) {
343 return -1;
344 }
345 return normalized1 - normalized2;
346 });
347 });
348 }
349 };
350 Geometry.prototype.getY0Value = function () {
351 var _a = this,
352 attrs = _a.attrs,
353 props = _a.props;
354 var chart = props.chart;
355 var field = attrs.y.field;
356 var scale = chart.getScale(field);
357 return chart.scale.getZeroValue(scale);
358 };
359 // 根据各属性映射的值域来获取真正的绘图属性
360 Geometry.prototype._getShapeStyle = function (shape, origin) {
361 var _a = this,
362 context = _a.context,
363 props = _a.props,
364 geomType = _a.geomType;
365 var theme = context.theme;
366 var shapeTheme = theme.shape[geomType] || {};
367 var defaultShapeStyle = shapeTheme.default;
368 var shapeThemeStyle = shapeTheme[shape];
369 var style = props.style;
370 var shapeStyle = __assign(__assign({}, defaultShapeStyle), shapeThemeStyle);
371 if (!style || !isObject(style)) {
372 return shapeStyle;
373 }
374 // @ts-ignore
375 var field = style.field,
376 styles = __rest(style, ["field"]);
377 var value = field ? origin[field] : origin;
378 each(styles, function (attr, key) {
379 if (isFunction(attr)) {
380 var attrValue = attr(value);
381 if (!attrValue) {
382 return;
383 }
384 shapeStyle[key] = attrValue;
385 return;
386 }
387 shapeStyle[key] = attr;
388 });
389 return shapeStyle;
390 };
391 /**
392 * 数据映射到视图属性核心逻辑
393 * x、y 每个元素走 normalize 然后 convertPoint
394 * color、size、shape
395 * 如果是Linear,则每个元素 走 mapping
396 * 如果是Category/Identity 则第一个元素走 mapping
397 */
398 Geometry.prototype._mapping = function (records) {
399 var _a = this,
400 attrs = _a.attrs,
401 props = _a.props,
402 attrController = _a.attrController;
403 var coord = props.coord;
404 var _b = attrController.getAttrsByLinear(),
405 linearAttrs = _b.linearAttrs,
406 nonlinearAttrs = _b.nonlinearAttrs;
407 var defaultAttrValues = attrController.getDefaultAttrValues();
408 var mappedRecords = [];
409 for (var i = 0, len = records.length; i < len; i++) {
410 var record = records[i];
411 var children = record.children;
412 var attrValues = __assign({}, defaultAttrValues);
413 var firstChild = children[0];
414 if (children.length === 0) {
415 mappedRecords.push(__assign({}, record));
416 continue;
417 }
418 // 非线性映射
419 for (var k = 0, len_2 = nonlinearAttrs.length; k < len_2; k++) {
420 var attrName = nonlinearAttrs[k];
421 var attr = attrs[attrName];
422 // 非线性映射只用映射第一项就可以了
423 attrValues[attrName] = attr.mapping(firstChild[attr.field], firstChild.origin);
424 }
425 // 线性属性映射
426 var mappedChildren = [];
427 for (var j = 0, childrenLen = children.length; j < childrenLen; j++) {
428 var child = children[j];
429 var normalized = {};
430 for (var k = 0; k < linearAttrs.length; k++) {
431 var attrName = linearAttrs[k];
432 var attr = attrs[attrName];
433 var value = child[attr.field];
434 // 分类属性的线性映射
435 if (attrController.isGroupAttr(attrName)) {
436 attrValues[attrName] = attr.mapping(value, child);
437 } else {
438 normalized[attrName] = attr.normalize(value);
439 }
440 }
441 var _c = coord.convertPoint({
442 x: normalized.x,
443 y: normalized.y
444 }),
445 x = _c.x,
446 y = _c.y;
447 // 获取 shape 的 style
448 var origin_1 = child.origin;
449 var shapeName = attrValues.shape;
450 var shape = this._getShapeStyle(shapeName, origin_1);
451 var selected = this.isSelected(child);
452 mappedChildren.push(__assign(__assign(__assign({}, child), attrValues), {
453 normalized: normalized,
454 x: x,
455 y: y,
456 shapeName: shapeName,
457 shape: shape,
458 selected: selected
459 }));
460 }
461 mappedRecords.push(__assign(__assign({}, record), {
462 children: mappedChildren
463 }));
464 }
465 return mappedRecords;
466 };
467 // 数据映射
468 Geometry.prototype.mapping = function () {
469 var dataRecords = this.dataRecords;
470 // 数据映射
471 this.records = this._mapping(dataRecords);
472 return this.records;
473 };
474 Geometry.prototype.getClip = function () {
475 var _a = this.props,
476 coord = _a.coord,
477 viewClip = _a.viewClip;
478 var contentWidth = coord.width,
479 contentHeight = coord.height,
480 left = coord.left,
481 top = coord.top;
482 if (viewClip) {
483 return {
484 type: 'rect',
485 style: {
486 x: left,
487 y: top,
488 width: contentWidth,
489 height: contentHeight
490 }
491 };
492 }
493 return null;
494 };
495 Geometry.prototype.getAttr = function (attrName) {
496 return this.attrController.getAttr(attrName);
497 };
498 Geometry.prototype.getXScale = function () {
499 return this.getAttr('x').scale;
500 };
501 Geometry.prototype.getYScale = function () {
502 return this.getAttr('y').scale;
503 };
504 Geometry.prototype._getXSnap = function (invertPointX) {
505 var xScale = this.getXScale();
506 if (xScale.isCategory) {
507 return xScale.invert(invertPointX);
508 }
509 // linear 类型
510 var invertValue = xScale.invert(invertPointX);
511 var values = xScale.values;
512 var len = values.length;
513 // 如果只有1个点直接返回第1个点
514 if (len === 1) {
515 return values[0];
516 }
517 // 第1个点和第2个点之间
518 if ((values[0] + values[1]) / 2 > invertValue) {
519 return values[0];
520 }
521 // 最后2个点
522 if ((values[len - 2] + values[len - 1]) / 2 <= invertValue) {
523 return values[len - 1];
524 }
525 for (var i = 1; i < len; i++) {
526 // 中间的点
527 if ((values[i - 1] + values[i]) / 2 <= invertValue && (values[i + 1] + values[i]) / 2 > invertValue) {
528 return values[i];
529 }
530 }
531 return null;
532 };
533 Geometry.prototype._getYSnapRecords = function (invertPointY, records) {
534 var yScale = this.getYScale();
535 var yField = yScale.field;
536 var yValue = yScale.invert(invertPointY);
537 // category
538 if (yScale.isCategory) {
539 return records.filter(function (record) {
540 return record[FIELD_ORIGIN][yField] === yValue;
541 });
542 }
543 // linear
544 return records.filter(function (record) {
545 var rangeY = record[yField];
546 if (rangeY[0] <= yValue && rangeY[1] >= yValue) {
547 return true;
548 }
549 return false;
550 });
551 };
552 // 把 records 拍平
553 Geometry.prototype.flatRecords = function () {
554 var records = this.records;
555 return records.reduce(function (prevRecords, record) {
556 return prevRecords.concat(record.children);
557 }, []);
558 };
559 Geometry.prototype.getSnapRecords = function (point, inCoordRange) {
560 var props = this.props;
561 var coord = props.coord,
562 adjust = props.adjust;
563 var invertPoint = coord.invertPoint(point);
564 var xScale = this.getXScale();
565 var yScale = this.getYScale();
566 // 如果不在coord坐标范围内,直接返回空
567 // if (invertPoint.x < 0 || invertPoint.y < 0) {
568 // return [];
569 // }
570 // 是否调整 point,默认为不调整
571 if (inCoordRange) {
572 var xRange = xScale.range;
573 var yRange = yScale.range;
574 // 如果 inCoordRange=true,当 point 不在 coord 坐标范围内时,调整到 range 内
575 invertPoint.x = Math.min(Math.max(invertPoint.x, xRange[0]), xRange[1]);
576 invertPoint.y = Math.min(Math.max(invertPoint.y, yRange[0]), yRange[1]);
577 }
578 var records = this.flatRecords();
579 var xValue = xScale.invert(invertPoint.x);
580 var yValue = yScale.invert(invertPoint.y);
581 var coordPoint = coord.convertPoint(invertPoint);
582 var coordRecord = {
583 // 坐标点
584 x: coordPoint.x,
585 y: coordPoint.y,
586 xValue: xValue,
587 yValue: yValue,
588 xText: xScale.getText(xValue),
589 yText: yScale.getText(yValue)
590 };
591 // 处理饼图
592 if (adjust === 'stack' && coord.isPolar && coord.transposed) {
593 // 弧度在半径范围内
594 if (invertPoint.x >= 0 && invertPoint.x <= 1) {
595 var snapRecords = this._getYSnapRecords(invertPoint.y, records);
596 return snapRecords;
597 }
598 }
599 var rst = [];
600 var value = this._getXSnap(invertPoint.x);
601 if (isNull(value)) {
602 return rst;
603 }
604 var xField = xScale.field;
605 var yField = yScale.field;
606 for (var i = 0, len = records.length; i < len; i++) {
607 var record = __assign(__assign({}, records[i]), {
608 xField: xField,
609 yField: yField,
610 coord: coordRecord
611 });
612 var originValue = record[FIELD_ORIGIN][xField];
613 if (xScale.type === 'timeCat' && toTimeStamp(originValue) === value) {
614 rst.push(record);
615 } else if (originValue === value) {
616 rst.push(record);
617 }
618 }
619 return rst;
620 };
621 Geometry.prototype.getRecords = function (data, field) {
622 if (field === void 0) {
623 field = 'xfield';
624 }
625 var records = this.flatRecords();
626 var xScale = this.getXScale();
627 var yScale = this.getYScale();
628 var xField = xScale.field;
629 var yField = yScale.field;
630 var value = data[xField];
631 var rst = [];
632 for (var i = 0, len = records.length; i < len; i++) {
633 var record = __assign(__assign({}, records[i]), {
634 xField: xField,
635 yField: yField
636 });
637 var originValue = record[FIELD_ORIGIN][field === 'xfield' ? xField : yField];
638 if (originValue === value) {
639 rst.push(record);
640 }
641 }
642 return rst;
643 };
644 Geometry.prototype.getLegendItems = function () {
645 var _a = this,
646 attrController = _a.attrController,
647 records = _a.records;
648 var colorAttr = attrController.getAttr('color');
649 if (!colorAttr) return null;
650 var scale = colorAttr.scale;
651 var isCategory = scale.isCategory,
652 field = scale.field;
653 if (!isCategory) return null;
654 var flatRecords = records ? this.flatRecords() : [];
655 var ticks = scale.getTicks();
656 var items = ticks.map(function (tick) {
657 var text = tick.text,
658 tickValue = tick.tickValue;
659 var record = find(flatRecords, function (item) {
660 if (!item) return false;
661 var origin = item.origin;
662 return origin[field] === tickValue;
663 });
664 // @ts-ignore
665 var color = record ? record.color : colorAttr.mapping(tickValue);
666 return {
667 field: scale.field,
668 color: color,
669 name: text,
670 tickValue: tickValue
671 };
672 });
673 return items;
674 };
675 return Geometry;
676}(Selection);
677export default Geometry;
\No newline at end of file