UNPKG

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