@antv/f2
Version:
Charts for mobile visualization.
653 lines • 21.7 kB
JavaScript
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
import _get from "@babel/runtime/helpers/esm/get";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
var _excluded = ["field"];
import { isFunction, each, upperFirst, mix, groupToMap, isObject, flatten } from '@antv/util';
import Selection from './selection';
import { getAdjust } from '@antv/adjust';
import { toTimeStamp } from '../../util/index';
import AttrController from '../../controller/attr';
import equal from '../../base/equal';
// 保留原始数据的字段
var FIELD_ORIGIN = 'origin';
var Geometry = /*#__PURE__*/function (_Selection) {
_inherits(Geometry, _Selection);
var _super = _createSuper(Geometry);
function Geometry(props, context) {
var _this;
_classCallCheck(this, Geometry);
_this = _super.call(this, props, context);
_this.isGeometry = true;
// x 轴居中
_this.justifyContent = false;
// y 轴是否从0开始
_this.startOnZero = false;
// 是否连接空值
_this.connectNulls = false;
// 是否需要排序
_this.sortable = false;
mix(_assertThisInitialized(_this), _this.getDefaultCfg());
var chart = props.chart,
coord = props.coord;
var attrsRange = _this._getThemeAttrsRange();
_this.attrController = new AttrController(chart.scale, attrsRange);
var _assertThisInitialize = _assertThisInitialized(_this),
attrController = _assertThisInitialize.attrController,
justifyContent = _assertThisInitialize.justifyContent;
var attrOptions = attrController.getAttrOptions(props, !coord.isCyclic() || justifyContent);
attrController.create(attrOptions);
return _this;
}
_createClass(Geometry, [{
key: "getDefaultCfg",
value: function getDefaultCfg() {
return {};
}
}, {
key: "willReceiveProps",
value: function willReceiveProps(nextProps) {
_get(_getPrototypeOf(Geometry.prototype), "willReceiveProps", this).call(this, nextProps);
var lastProps = this.props,
attrController = this.attrController,
justifyContent = this.justifyContent;
var nextData = nextProps.data,
nextAdjust = nextProps.adjust,
nextZoomRange = nextProps.zoomRange,
coord = nextProps.coord;
var lastData = lastProps.data,
lastAdjust = lastProps.adjust,
lastZoomRange = lastProps.zoomRange;
var justifyContentCenter = !coord.isCyclic() || justifyContent;
var nextAttrOptions = attrController.getAttrOptions(nextProps, justifyContentCenter);
var lastAttrOptions = attrController.getAttrOptions(lastProps, justifyContentCenter);
if (!equal(nextAttrOptions, lastAttrOptions)) {
attrController.update(nextAttrOptions);
this.records = null;
}
// 重新处理数据
if (nextData !== lastData) {
this.records = null;
}
// 重新处理数据
if (nextAdjust !== lastAdjust) {
this.records = null;
}
// zoomRange发生变化,records也需要重新计算
if (!equal(nextZoomRange, lastZoomRange)) {
this.records = null;
}
}
}, {
key: "willMount",
value: function willMount() {
this._createAttrs();
if (!this.records) {
this._processData();
}
}
}, {
key: "willUpdate",
value: function willUpdate() {
this._createAttrs();
if (!this.records) {
this._processData();
}
}
}, {
key: "didMount",
value: function didMount() {
_get(_getPrototypeOf(Geometry.prototype), "didMount", this).call(this);
this._initEvent();
}
}, {
key: "_createAttrs",
value: function _createAttrs() {
var attrController = this.attrController;
attrController.attrs = {};
this.attrs = attrController.getAttrs();
}
}, {
key: "_getThemeAttrsRange",
value: function _getThemeAttrsRange() {
var context = this.context,
props = this.props,
geomType = this.geomType;
var coord = props.coord;
var theme = context.theme;
var colors = theme.colors,
sizes = theme.sizes,
shapes = theme.shapes;
return {
x: coord.x,
y: coord.y,
color: colors,
size: sizes,
shape: shapes[geomType]
};
}
}, {
key: "_adjustScales",
value: function _adjustScales() {
var attrs = this.attrs,
props = this.props,
defaultStartOnZero = this.startOnZero;
var chart = props.chart,
_props$startOnZero = props.startOnZero,
startOnZero = _props$startOnZero === void 0 ? defaultStartOnZero : _props$startOnZero,
coord = props.coord,
adjust = props.adjust;
var isPolar = coord.isPolar,
transposed = coord.transposed;
var y = attrs.y;
var yField = y.field;
// 如果从 0 开始,只调整 y 轴 scale
if (startOnZero) {
var _y = attrs.y;
chart.scale.adjustStartZero(_y.scale);
}
// 饼图的scale调整,关闭nice
if (isPolar && transposed && (adjust === 'stack' || (adjust === null || adjust === void 0 ? void 0 : adjust.type) === 'stack')) {
var _y2 = attrs.y;
chart.scale.adjustPieScale(_y2.scale);
}
if (adjust === 'stack' || (adjust === null || adjust === void 0 ? void 0 : adjust.type) === 'stack') {
this._updateStackRange(yField, y.scale, this.dataArray);
}
}
}, {
key: "_groupData",
value: function _groupData(data) {
var attrController = this.attrController;
var groupScales = attrController.getGroupScales();
if (!groupScales.length) {
return [{
children: data
}];
}
var names = [];
groupScales.forEach(function (scale) {
var field = scale.field;
names.push(field);
});
var groups = groupToMap(data, names);
var records = [];
for (var key in groups) {
records.push({
key: key.replace(/^_/, ''),
children: groups[key]
});
}
return records;
}
}, {
key: "_saveOrigin",
value: function _saveOrigin(originData) {
var len = originData.length;
var data = new Array(len);
for (var i = 0; i < len; i++) {
var record = originData[i];
data[i] = _objectSpread(_objectSpread({}, record), {}, _defineProperty({}, FIELD_ORIGIN, record));
}
return data;
}
}, {
key: "_numberic",
value: function _numberic(data) {
var attrs = this.attrs;
var scales = [attrs.x.scale, attrs.y.scale];
for (var j = 0, len = data.length; j < len; j++) {
var obj = data[j];
var count = scales.length;
for (var i = 0; i < count; i++) {
var scale = scales[i];
if (scale.isCategory) {
var field = scale.field;
obj[field] = scale.translate(obj[field]);
}
}
}
}
}, {
key: "_adjustData",
value: function _adjustData(records) {
var attrs = this.attrs,
props = this.props;
var adjust = props.adjust;
// groupedArray 是二维数组
var groupedArray = records.map(function (record) {
return record.children;
});
if (!adjust) {
return groupedArray;
}
var adjustCfg = typeof adjust === 'string' ? {
type: adjust
} : adjust;
var adjustType = upperFirst(adjustCfg.type);
var AdjustConstructor = getAdjust(adjustType);
if (!AdjustConstructor) {
throw new Error('not support such adjust : ' + adjust);
}
if (adjustType === 'Dodge') {
for (var i = 0, len = groupedArray.length; i < len; i++) {
// 如果是dodge, 需要处理数字再处理
this._numberic(groupedArray[i]);
}
adjustCfg.adjustNames = ['x'];
}
var x = attrs.x,
y = attrs.y;
adjustCfg.xField = x.field;
adjustCfg.yField = y.field;
var adjustInstance = new AdjustConstructor(adjustCfg);
var adjustData = adjustInstance.process(groupedArray);
this.adjust = {
type: adjustCfg.type,
adjust: adjustInstance
};
// process 返回的是新数组,所以要修改 records
records.forEach(function (record, index) {
record.children = adjustData[index];
});
return adjustData;
}
}, {
key: "_updateStackRange",
value: function _updateStackRange(field, scale, dataArray) {
var flattenArray = flatten(dataArray);
var min = Infinity;
var max = -Infinity;
for (var i = 0, len = flattenArray.length; i < len; i++) {
var obj = flattenArray[i];
var tmpMin = Math.min.apply(null, obj[field]);
var tmpMax = Math.max.apply(null, obj[field]);
if (tmpMin < min) {
min = tmpMin;
}
if (tmpMax > max) {
max = tmpMax;
}
}
if (min !== scale.min || max !== scale.max) {
scale.change({
min: min,
max: max
});
}
}
}, {
key: "_processData",
value: function _processData() {
var props = this.props;
var originData = props.data;
var data = this._saveOrigin(originData);
// 根据分类度量进行数据分组
var records = this._groupData(data);
// 根据adjust分组
var dataArray = this._adjustData(records);
this.dataArray = dataArray;
// scale适配调整,主要是调整 y 轴是否从 0 开始 以及 饼图
this._adjustScales();
// 数据排序(非必须)
if (this.sortable) {
this._sortData(records);
}
this.records = records;
}
}, {
key: "_sortData",
value: function _sortData(records) {
var xScale = this.getXScale();
var field = xScale.field,
type = xScale.type;
if (type !== 'identity' && xScale.values.length > 1) {
each(records, function (_ref) {
var children = _ref.children;
children.sort(function (record1, record2) {
if (type === 'timeCat') {
return toTimeStamp(record1[FIELD_ORIGIN][field]) - toTimeStamp(record2[FIELD_ORIGIN][field]);
}
return xScale.translate(record1[FIELD_ORIGIN][field]) - xScale.translate(record2[FIELD_ORIGIN][field]);
});
});
}
}
}, {
key: "_initEvent",
value: function _initEvent() {
var _this2 = this;
var container = this.container,
props = this.props;
var canvas = container.get('canvas');
['onPressStart', 'onPress', 'onPressEnd', 'onPan', 'onPanStart', 'onPanEnd'].forEach(function (eventName) {
if (props[eventName]) {
canvas.on(eventName.substr(2).toLowerCase(), function (ev) {
ev.geometry = _this2;
props[eventName](ev);
});
}
});
}
}, {
key: "getY0Value",
value: function getY0Value() {
var attrs = this.attrs,
props = this.props;
var chart = props.chart;
var field = attrs.y.field;
var scale = chart.getScale(field);
return chart.scale.getZeroValue(scale);
}
// 根据各属性映射的值域来获取真正的绘图属性
}, {
key: "_getShapeStyle",
value: function _getShapeStyle(shape, origin) {
var context = this.context,
props = this.props,
geomType = this.geomType;
var theme = context.theme;
var shapeTheme = theme.shape[geomType] || {};
var defaultShapeStyle = shapeTheme.default;
var shapeThemeStyle = shapeTheme[shape];
var style = props.style;
var shapeStyle = _objectSpread(_objectSpread({}, defaultShapeStyle), shapeThemeStyle);
if (!style || !isObject(style)) {
return shapeStyle;
}
// @ts-ignore
var field = style.field,
styles = _objectWithoutProperties(style, _excluded);
var value = field ? origin[field] : origin;
each(styles, function (attr, key) {
if (isFunction(attr)) {
shapeStyle[key] = attr(value);
} else {
shapeStyle[key] = attr;
}
});
return shapeStyle;
}
/**
* 数据映射到视图属性核心逻辑
* x、y 每个元素走 normalize 然后 convertPoint
* color、size、shape
* 如果是Linear,则每个元素 走 mapping
* 如果是Category/Identity 则第一个元素走 mapping
*/
}, {
key: "_mapping",
value: function _mapping(records) {
var attrs = this.attrs,
props = this.props,
attrController = this.attrController;
var coord = props.coord;
var _attrController$getAt = attrController.getAttrsByLinear(),
linearAttrs = _attrController$getAt.linearAttrs,
nonlinearAttrs = _attrController$getAt.nonlinearAttrs;
var defaultAttrValues = attrController.getDefaultAttrValues();
for (var i = 0, len = records.length; i < len; i++) {
var record = records[i];
var children = record.children;
var attrValues = _objectSpread({}, defaultAttrValues);
var firstChild = children[0];
if (children.length === 0) {
continue;
}
// 非线性映射
for (var k = 0, _len = nonlinearAttrs.length; k < _len; k++) {
var attrName = nonlinearAttrs[k];
var attr = attrs[attrName];
// 非线性映射只用映射第一项就可以了
attrValues[attrName] = attr.mapping(firstChild[attr.field]);
}
// 线性属性映射
for (var j = 0, childrenLen = children.length; j < childrenLen; j++) {
var child = children[j];
var normalized = {};
for (var _k = 0; _k < linearAttrs.length; _k++) {
var _attrName = linearAttrs[_k];
var _attr = attrs[_attrName];
// 分类属性的线性映射
if (attrController.isGroupAttr(_attrName)) {
attrValues[_attrName] = _attr.mapping(child[_attr.field], child);
} else {
normalized[_attrName] = _attr.normalize(child[_attr.field]);
}
}
var _coord$convertPoint = coord.convertPoint({
x: normalized.x,
y: normalized.y
}),
x = _coord$convertPoint.x,
y = _coord$convertPoint.y;
// 获取 shape 的 style
var shapeName = attrValues.shape;
var shape = this._getShapeStyle(shapeName, child.origin);
var selected = this.isSelected(child);
mix(child, attrValues, {
normalized: normalized,
x: x,
y: y,
shapeName: shapeName,
shape: shape,
selected: selected
});
}
}
return records;
}
// 数据映射
}, {
key: "mapping",
value: function mapping() {
var records = this.records;
// 数据映射
this._mapping(records);
return records;
}
}, {
key: "getClip",
value: function getClip() {
var _this$props = this.props,
coord = _this$props.coord,
viewClip = _this$props.viewClip;
var contentWidth = coord.width,
contentHeight = coord.height,
left = coord.left,
top = coord.top;
if (viewClip) {
return {
type: 'rect',
attrs: {
x: left,
y: top,
width: contentWidth,
height: contentHeight
}
};
}
return null;
}
}, {
key: "getAttr",
value: function getAttr(attrName) {
return this.attrController.getAttr(attrName);
}
}, {
key: "getXScale",
value: function getXScale() {
return this.getAttr('x').scale;
}
}, {
key: "getYScale",
value: function getYScale() {
return this.getAttr('y').scale;
}
}, {
key: "_getXSnap",
value: function _getXSnap(invertPointX) {
var xScale = this.getXScale();
if (xScale.isCategory) {
return xScale.invert(invertPointX);
}
// linear 类型
var invertValue = xScale.invert(invertPointX);
var values = xScale.values;
var len = values.length;
// 如果只有1个点直接返回第1个点
if (len === 1) {
return values[0];
}
// 第1个点和第2个点之间
if ((values[0] + values[1]) / 2 > invertValue) {
return values[0];
}
// 最后2个点
if ((values[len - 2] + values[len - 1]) / 2 <= invertValue) {
return values[len - 1];
}
for (var i = 1; i < len; i++) {
// 中间的点
if ((values[i - 1] + values[i]) / 2 <= invertValue && (values[i + 1] + values[i]) / 2 > invertValue) {
return values[i];
}
}
return null;
}
}, {
key: "_getYSnapRecords",
value: function _getYSnapRecords(invertPointY, records) {
var yScale = this.getYScale();
var yField = yScale.field;
var yValue = yScale.invert(invertPointY);
// category
if (yScale.isCategory) {
return records.filter(function (record) {
return record[FIELD_ORIGIN][yField] === yValue;
});
}
// linear
return records.filter(function (record) {
var rangeY = record[yField];
if (rangeY[0] <= yValue && rangeY[1] >= yValue) {
return true;
}
return false;
});
}
// 把 records 拍平
}, {
key: "flatRecords",
value: function flatRecords() {
var records = this.records;
return records.reduce(function (prevRecords, record) {
return prevRecords.concat(record.children);
}, []);
}
}, {
key: "getSnapRecords",
value: function getSnapRecords(point, inCoordRange) {
var props = this.props;
var coord = props.coord,
adjust = props.adjust;
var invertPoint = coord.invertPoint(point);
var xScale = this.getXScale();
var yScale = this.getYScale();
// 如果不在coord坐标范围内,直接返回空
// if (invertPoint.x < 0 || invertPoint.y < 0) {
// return [];
// }
// 是否调整 point,默认为不调整
if (inCoordRange) {
var xRange = xScale.range;
var yRange = yScale.range;
// 如果 inCoordRange=true,当 point 不在 coord 坐标范围内时,调整到 range 内
invertPoint.x = Math.min(Math.max(invertPoint.x, xRange[0]), xRange[1]);
invertPoint.y = Math.min(Math.max(invertPoint.y, yRange[0]), yRange[1]);
}
var records = this.flatRecords();
// 处理饼图
if (adjust === 'stack' && coord.isPolar && coord.transposed) {
// 弧度在半径范围内
if (invertPoint.x >= 0 && invertPoint.x <= 1) {
var snapRecords = this._getYSnapRecords(invertPoint.y, records);
return snapRecords;
}
}
var rst = [];
var value = this._getXSnap(invertPoint.x);
if (!value) {
return rst;
}
var xField = xScale.field;
var yField = yScale.field;
for (var i = 0, len = records.length; i < len; i++) {
var record = _objectSpread(_objectSpread({}, records[i]), {}, {
xField: xField,
yField: yField
});
var originValue = record[FIELD_ORIGIN][xField];
if (xScale.type === 'timeCat' && toTimeStamp(originValue) === value) {
rst.push(record);
} else if (originValue === value) {
rst.push(record);
}
}
return rst;
}
}, {
key: "getRecords",
value: function getRecords(data) {
var field = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'xfield';
var records = this.flatRecords();
var xScale = this.getXScale();
var yScale = this.getYScale();
var xField = xScale.field;
var yField = yScale.field;
var value = data[xField];
var rst = [];
for (var i = 0, len = records.length; i < len; i++) {
var record = _objectSpread(_objectSpread({}, records[i]), {}, {
xField: xField,
yField: yField
});
var originValue = record[FIELD_ORIGIN][field === 'xfield' ? xField : yField];
if (originValue === value) {
rst.push(record);
}
}
return rst;
}
}, {
key: "getLegendItems",
value: function getLegendItems() {
var attrController = this.attrController;
var colorAttr = attrController.getAttr('color');
if (!colorAttr) return null;
var scale = colorAttr.scale;
if (!scale.isCategory) return null;
var ticks = scale.getTicks();
var items = ticks.map(function (tick) {
var text = tick.text,
tickValue = tick.tickValue;
var color = colorAttr.mapping(tickValue);
return {
field: scale.field,
color: color,
name: text,
tickValue: tickValue
};
});
return items;
}
}]);
return Geometry;
}(Selection);
export default Geometry;