NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/esm/geometry/base.js

1346 lines
49 KiB
Java
Raw Normal View History

2023-09-14 14:47:11 +08:00
import { __assign, __extends } from "tslib";
import { getAdjust as getAdjustClass } from '@antv/adjust';
import { getAttribute as getAttributeClass } from '@antv/attr';
import { clone, deepMix, each, flatten, get, isArray, isEmpty, isEqual, isFunction, isNil, isNumber, isObject, isPlainObject, isString, set, } from '@antv/util';
import { doGroupAppearAnimate, getDefaultAnimateCfg } from '../animate';
import Base from '../base';
import { FIELD_ORIGIN, GROUP_ATTRS } from '../constant';
import { uniq } from '../util/helper';
import Element from './element';
import { getGeometryLabel } from './label';
import { getShapeFactory } from './shape/base';
import { group } from './util/group-data';
import { isModelChange } from './util/is-model-change';
import { parseFields } from './util/parse-fields';
// 根据 elementId 查找对应的 label因为有可能一个 element 对应多个 labels所以在给 labels 打标识时做了处理
// 打标规则详见 ./label/base.ts#L263
function filterLabelsById(id, labelsMap) {
var labels = [];
each(labelsMap, function (label, labelId) {
var elementId = labelId.split(' ')[0];
if (elementId === id) {
labels.push(label);
}
});
return labels;
}
/**
* Geometry 几何标记基类主要负责数据到图形属性的映射以及绘制逻辑
*/
var Geometry = /** @class */ (function (_super) {
__extends(Geometry, _super);
/**
* 创建 Geometry 实例
* @param cfg
*/
function Geometry(cfg) {
var _this = _super.call(this, cfg) || this;
/** Geometry 几何标记类型。 */
_this.type = 'base';
// 内部产生的属性
/** Attribute map */
_this.attributes = {};
/** Element map */
_this.elements = [];
/** 使用 key-value 结构存储 Elementkey 为每个 Element 实例对应的唯一 ID */
_this.elementsMap = {};
/** animate 配置项 */
_this.animateOption = true;
/** 图形属性映射配置 */
_this.attributeOption = {};
/** 存储上一次渲染时的 element 映射表,用于更新逻辑 */
_this.lastElementsMap = {};
/** 是否生成多个点来绘制图形。 */
_this.generatePoints = false;
/** 存储发生图形属性映射前的数据 */
_this.beforeMappingData = null;
_this.adjusts = {};
_this.idFields = [];
_this.hasSorted = false;
_this.isCoordinateChanged = false;
var container = cfg.container, labelsContainer = cfg.labelsContainer, coordinate = cfg.coordinate, data = cfg.data, _a = cfg.sortable, sortable = _a === void 0 ? false : _a, _b = cfg.visible, visible = _b === void 0 ? true : _b, theme = cfg.theme, _c = cfg.scales, scales = _c === void 0 ? {} : _c, _d = cfg.scaleDefs, scaleDefs = _d === void 0 ? {} : _d;
_this.container = container;
_this.labelsContainer = labelsContainer;
_this.coordinate = coordinate;
_this.data = data;
_this.sortable = sortable;
_this.visible = visible;
_this.userTheme = theme;
_this.scales = scales;
_this.scaleDefs = scaleDefs;
return _this;
}
/**
* 配置 position 通道映射规则
*
* @example
* ```typescript
* // 数据结构: [{ x: 'A', y: 10, color: 'red' }]
* geometry.position('x*y');
* geometry.position([ 'x', 'y' ]);
* geometry.position({
* fields: [ 'x', 'y' ],
* });
* ```
*
* @param cfg 映射规则
* @returns
*/
Geometry.prototype.position = function (cfg) {
var positionCfg = cfg;
if (!isPlainObject(cfg)) {
// 字符串字段或者数组字段
positionCfg = {
fields: parseFields(cfg),
};
}
var fields = get(positionCfg, 'fields');
if (fields.length === 1) {
// 默认填充一维 1*xx
fields.unshift('1');
set(positionCfg, 'fields', fields);
}
set(this.attributeOption, 'position', positionCfg);
return this;
};
Geometry.prototype.color = function (field, cfg) {
this.createAttrOption('color', field, cfg);
return this;
};
Geometry.prototype.shape = function (field, cfg) {
this.createAttrOption('shape', field, cfg);
return this;
};
Geometry.prototype.size = function (field, cfg) {
this.createAttrOption('size', field, cfg);
return this;
};
/**
* 设置数据调整方式G2 目前内置了四种类型
* 1. dodge
* 2. stack
* 3. symmetric
* 4. jitter
*
*
* **Tip**
* + 对于 'dodge' 类型可以额外进行如下属性的配置:
* ```typescript
* geometry.adjust('dodge', {
* marginRatio: 0, // 取 0 到 1 范围的值(相对于每个柱子宽度),用于控制一个分组中柱子之间的间距
* dodgeBy: 'x', // 该属性只对 'dodge' 类型生效,声明以哪个数据字段为分组依据
* });
* ```
*
* + 对于 'stack' 类型可以额外进行如下属性的配置:
* ```typescript
* geometry.adjust('stack', {
* reverseOrder: false, // 用于控制是否对数据进行反序操作
* });
* ```
*
* @example
* ```typescript
* geometry.adjust('stack');
*
* geometry.adjust({
* type: 'stack',
* reverseOrder: false,
* });
*
* // 组合使用 adjust
* geometry.adjust([ 'stack', 'dodge' ]);
*
* geometry.adjust([
* { type: 'stack' },
* { type: 'dodge', dodgeBy: 'x' },
* ]);
* ```
*
* @param adjustCfg 数据调整配置
* @returns
*/
Geometry.prototype.adjust = function (adjustCfg) {
var adjusts = adjustCfg;
if (isString(adjustCfg) || isPlainObject(adjustCfg)) {
adjusts = [adjustCfg];
}
each(adjusts, function (adjust, index) {
if (!isObject(adjust)) {
adjusts[index] = { type: adjust };
}
});
this.adjustOption = adjusts;
return this;
};
Geometry.prototype.style = function (field, styleFunc) {
if (isString(field)) {
var fields = parseFields(field);
this.styleOption = {
fields: fields,
callback: styleFunc,
};
}
else {
var _a = field, fields = _a.fields, callback = _a.callback, cfg = _a.cfg;
if (fields || callback || cfg) {
this.styleOption = field;
}
else {
this.styleOption = {
cfg: field,
};
}
}
return this;
};
Geometry.prototype.tooltip = function (field, cfg) {
if (isString(field)) {
var fields = parseFields(field);
this.tooltipOption = {
fields: fields,
callback: cfg,
};
}
else {
this.tooltipOption = field;
}
return this;
};
/**
* Geometry 动画配置
*
* + `animate(false)` 关闭动画
* + `animate(true)` 开启动画默认开启
*
* 我们将动画分为四个场景
* 1. appear: 图表第一次加载时的入场动画
* 2. enter: 图表绘制完成发生更新后产生的新图形的进场动画
* 3. update: 图表绘制完成数据发生变更后有状态变更的图形的更新动画
* 4. leave: 图表绘制完成数据发生变更后被销毁图形的销毁动画
*
* @example
* ```typescript
* animate({
* enter: {
* duration: 1000, // enter 动画执行时间
* },
* leave: false, // 关闭 leave 销毁动画
* });
* ```
*
* @param cfg 动画配置
* @returns
*/
Geometry.prototype.animate = function (cfg) {
this.animateOption = cfg;
return this;
};
Geometry.prototype.label = function (field, secondParam, thirdParam) {
if (isString(field)) {
var labelOption = {};
var fields = parseFields(field);
labelOption.fields = fields;
if (isFunction(secondParam)) {
labelOption.callback = secondParam;
}
else if (isPlainObject(secondParam)) {
labelOption.cfg = secondParam;
}
if (thirdParam) {
labelOption.cfg = thirdParam;
}
this.labelOption = labelOption;
}
else {
this.labelOption = field;
}
return this;
};
/**
* 设置状态对应的样式
*
* @example
* ```ts
* chart.interval().state({
* selected: {
* animate: { duration: 100, easing: 'easeLinear' },
* style: {
* lineWidth: 2,
* stroke: '#000',
* },
* },
* });
* ```
*
* 如果图形 shape 是由多个 shape 组成即为一个 G.Group 对象那么针对 group 中的每个 shape我们需要使用下列方式进行状态样式设置
* 如果我们为 group 中的每个 shape 设置了 'name' 属性(shape.set('name', 'xx'))则以 'name' 作为 key否则默认以索引值 shape 添加顺序 key
*
* ```ts
* chart.interval().shape('groupShape').state({
* selected: {
* style: {
* 0: { lineWidth: 2 },
* 1: { fillOpacity: 1 },
* }
* }
* });
* ```
*
* @param cfg 状态样式
*/
Geometry.prototype.state = function (cfg) {
this.stateOption = cfg;
return this;
};
/**
* 初始化 Geomtry 实例
* 创建 [[Attribute]] and [[Scale]] 实例进行数据处理包括分组数值化以及数据调整
*/
Geometry.prototype.init = function (cfg) {
if (cfg === void 0) { cfg = {}; }
this.setCfg(cfg);
this.initAttributes(); // 创建图形属性
// 数据加工:分组 -> 数字化 -> adjust
this.processData(this.data);
// 调整 scale
this.adjustScale();
};
/**
* Geometry 更新
* @param [cfg] 更新的配置
*/
Geometry.prototype.update = function (cfg) {
if (cfg === void 0) { cfg = {}; }
var data = cfg.data, isDataChanged = cfg.isDataChanged, isCoordinateChanged = cfg.isCoordinateChanged;
var _a = this, attributeOption = _a.attributeOption, lastAttributeOption = _a.lastAttributeOption;
if (!isEqual(attributeOption, lastAttributeOption)) {
// 映射发生改变,则重新创建图形属性
this.init(cfg);
}
else if (data && (isDataChanged || !isEqual(data, this.data))) {
// 数据发生变化
this.setCfg(cfg);
this.processData(data); // 数据加工:分组 -> 数字化 -> adjust
}
else {
// 有可能 coordinate 变化
this.setCfg(cfg);
}
// 调整 scale
this.adjustScale();
this.isCoordinateChanged = isCoordinateChanged;
};
/**
* 将原始数据映射至图形空间同时创建图形对象
*/
Geometry.prototype.paint = function (isUpdate) {
var _this = this;
if (isUpdate === void 0) { isUpdate = false; }
if (this.animateOption) {
this.animateOption = deepMix({}, getDefaultAnimateCfg(this.type, this.coordinate), this.animateOption);
}
this.defaultSize = undefined;
this.elements = [];
this.elementsMap = {};
var offscreenGroup = this.getOffscreenGroup();
offscreenGroup.clear();
var beforeMappingData = this.beforeMappingData;
var dataArray = this.beforeMapping(beforeMappingData);
var mappingArray = [];
for (var index = 0, length_1 = dataArray.length; index < length_1; index++) {
var eachGroup = dataArray[index];
var mappingData = this.mapping(eachGroup);
mappingArray.push(mappingData);
this.createElements(mappingData, index, isUpdate);
}
if (this.canDoGroupAnimation(isUpdate)) {
// 如果用户没有配置 appear.animation就默认走整体动画
var container = this.container;
var type = this.type;
var coordinate = this.coordinate;
var animateCfg = get(this.animateOption, 'appear');
var yScale = this.getYScale();
var yMinPoint = coordinate.convert({
x: 0,
y: yScale.scale(this.getYMinValue()),
});
doGroupAppearAnimate(container, animateCfg, type, coordinate, yMinPoint);
}
// 添加 label
if (this.labelOption) {
this.renderLabels(flatten(mappingArray), isUpdate);
}
this.dataArray = mappingArray;
// 销毁被删除的 elements
each(this.lastElementsMap, function (deletedElement) {
// 更新动画配置,用户有可能在更新之前有对动画进行配置操作
deletedElement.animate = _this.animateOption;
deletedElement.destroy();
});
this.lastElementsMap = this.elementsMap;
// 缓存,用于更新
this.lastAttributeOption = __assign({}, this.attributeOption);
if (this.visible === false) {
// 用户在初始化的时候声明 visible: false
this.changeVisible(false);
}
};
/**
* 清空当前 Geometry配置项仍保留但是内部创建的对象全部清空
* @override
*/
Geometry.prototype.clear = function () {
var _a = this, container = _a.container, geometryLabel = _a.geometryLabel, offscreenGroup = _a.offscreenGroup;
if (container) {
container.clear();
}
if (geometryLabel) {
geometryLabel.clear();
}
if (offscreenGroup) {
offscreenGroup.clear();
}
// 属性恢复至出厂状态
this.scaleDefs = undefined;
this.attributes = {};
this.scales = {};
this.elementsMap = {};
this.lastElementsMap = {};
this.elements = [];
this.adjusts = {};
this.dataArray = null;
this.beforeMappingData = null;
this.lastAttributeOption = undefined;
this.defaultSize = undefined;
this.idFields = [];
this.groupScales = undefined;
this.hasSorted = false;
this.isCoordinateChanged = false;
};
/**
* 销毁 Geometry 实例
*/
Geometry.prototype.destroy = function () {
this.clear();
var container = this.container;
container.remove(true);
if (this.offscreenGroup) {
this.offscreenGroup.remove(true);
this.offscreenGroup = null;
}
if (this.geometryLabel) {
this.geometryLabel.destroy();
this.geometryLabel = null;
}
this.theme = undefined;
this.shapeFactory = undefined;
_super.prototype.destroy.call(this);
};
/**
* 获取决定分组的图形属性对应的 scale 实例
* @returns
*/
Geometry.prototype.getGroupScales = function () {
return this.groupScales;
};
/**
* 根据名字获取图形属性实例
*/
Geometry.prototype.getAttribute = function (name) {
return this.attributes[name];
};
/** 获取 x 轴对应的 scale 实例。 */
Geometry.prototype.getXScale = function () {
return this.getAttribute('position').scales[0];
};
/** 获取 y 轴对应的 scale 实例。 */
Geometry.prototype.getYScale = function () {
return this.getAttribute('position').scales[1];
};
/**
* 获取决定分组的图形属性实例
*/
Geometry.prototype.getGroupAttributes = function () {
var rst = [];
each(this.attributes, function (attr) {
if (GROUP_ATTRS.includes(attr.type)) {
rst.push(attr);
}
});
return rst;
};
/** 获取图形属性默认的映射值。 */
Geometry.prototype.getDefaultValue = function (attrName) {
var value;
var attr = this.getAttribute(attrName);
if (attr && isEmpty(attr.scales)) {
// 获取映射至常量的值
value = attr.values[0];
}
return value;
};
/**
* 获取该数据发生图形映射后对应的 Attribute 图形空间数据
* @param attr Attribute 图形属性实例
* @param obj 需要进行映射的原始数据
* @returns
*/
Geometry.prototype.getAttributeValues = function (attr, obj) {
var params = [];
var scales = attr.scales;
for (var index = 0, length_2 = scales.length; index < length_2; index++) {
var scale = scales[index];
var field = scale.field;
if (scale.isIdentity) {
params.push(scale.values);
}
else {
params.push(obj[field]);
}
}
return attr.mapping.apply(attr, params);
};
Geometry.prototype.getAdjust = function (adjustType) {
return this.adjusts[adjustType];
};
/**
* 获取 shape 对应的 marker 样式
* @param shapeName shape 具体名字
* @param cfg marker 信息
* @returns
*/
Geometry.prototype.getShapeMarker = function (shapeName, cfg) {
var shapeFactory = this.getShapeFactory();
return shapeFactory.getMarker(shapeName, cfg);
};
/**
* 根据一定的规则查找 Geometry Elements
*
* ```typescript
* getElementsBy((element) => {
* const data = element.getData();
*
* return data.a === 'a';
* });
* ```
*
* @param condition 定义查找规则的回调函数
* @returns
*/
Geometry.prototype.getElementsBy = function (condition) {
return this.elements.filter(function (element) {
return condition(element);
});
};
/**
* 获取数据对应的唯一 id
* @param data Element 对应的绘制数据
* @returns
*/
Geometry.prototype.getElementId = function (data) {
data = isArray(data) ? data[0] : data;
var originData = data[FIELD_ORIGIN];
// 如果用户声明了使用哪些字段作为 id 值
if (this.idFields.length) {
var elementId = originData[this.idFields[0]];
for (var index = 1; index < this.idFields.length; index++) {
elementId += '-' + originData[this.idFields[index]];
}
return elementId;
}
var type = this.type;
var xScale = this.getXScale();
var yScale = this.getYScale();
var xField = xScale.field || 'x';
var yField = yScale.field || 'y';
var yVal = originData[yField];
var xVal;
if (xScale.type === 'identity') {
xVal = xScale.values[0];
}
else {
xVal = originData[xField];
}
var id;
if (type === 'interval' || type === 'schema') {
id = xVal;
}
else if (type === 'line' || type === 'area' || type === 'path') {
id = type;
}
else {
id = xVal + "-" + yVal;
}
var groupScales = this.groupScales;
for (var index = 0, length_3 = groupScales.length; index < length_3; index++) {
var groupScale = groupScales[index];
var field = groupScale.field;
id = id + "-" + originData[field];
}
// 用户在进行 dodge 类型的 adjust 调整的时候设置了 dodgeBy 属性
var dodgeAdjust = this.getAdjust('dodge');
if (dodgeAdjust) {
var dodgeBy = dodgeAdjust.dodgeBy;
if (dodgeBy) {
id = id + "-" + originData[dodgeBy];
}
}
if (this.getAdjust('jitter')) {
id = id + "-" + data.x + "-" + data.y;
}
return id;
};
/**
* 获取所有需要创建 scale 的字段名称
*/
Geometry.prototype.getScaleFields = function () {
var fields = [];
var tmpMap = {};
var _a = this, attributeOption = _a.attributeOption, labelOption = _a.labelOption, tooltipOption = _a.tooltipOption;
// 获取图形属性上的 fields
for (var attributeType in attributeOption) {
if (attributeOption.hasOwnProperty(attributeType)) {
var eachOpt = attributeOption[attributeType];
if (eachOpt.fields) {
uniq(eachOpt.fields, fields, tmpMap);
}
else if (eachOpt.values) {
// 考虑 size(10), shape('circle') 等场景
uniq(eachOpt.values, fields, tmpMap);
}
}
}
// 获取 label 上的字段
if (labelOption && labelOption.fields) {
uniq(labelOption.fields, fields, tmpMap);
}
// 获取 tooltip 上的字段
if (isObject(tooltipOption) && tooltipOption.fields) {
uniq(tooltipOption.fields, fields, tmpMap);
}
return fields;
};
/**
* 显示或者隐藏 geometry
* @param visible
*/
Geometry.prototype.changeVisible = function (visible) {
_super.prototype.changeVisible.call(this, visible);
var elements = this.elements;
for (var index = 0, length_4 = elements.length; index < length_4; index++) {
var element = elements[index];
element.changeVisible(visible);
}
if (visible) {
if (this.container) {
this.container.show();
}
if (this.labelsContainer) {
this.labelsContainer.show();
}
}
else {
if (this.container) {
this.container.hide();
}
if (this.labelsContainer) {
this.labelsContainer.hide();
}
}
};
/**
* 获取当前配置中的所有分组 & 分类的字段
* @return fields string[]
*/
Geometry.prototype.getGroupFields = function () {
var groupFields = [];
var tmpMap = {}; // 用于去重过滤
for (var index = 0, length_5 = GROUP_ATTRS.length; index < length_5; index++) {
var attributeName = GROUP_ATTRS[index];
var cfg = this.attributeOption[attributeName];
if (cfg && cfg.fields) {
uniq(cfg.fields, groupFields, tmpMap);
}
}
return groupFields;
};
/**
* 获得图形的 x y 字段
*/
Geometry.prototype.getXYFields = function () {
var _a = this.attributeOption.position.fields, x = _a[0], y = _a[1];
return [x, y];
};
/**
* 获取该 Geometry 下所有生成的 shapes
* @returns shapes
*/
Geometry.prototype.getShapes = function () {
return this.elements.map(function (element) { return element.shape; });
};
/**
* 获取虚拟 Group
* @returns
*/
Geometry.prototype.getOffscreenGroup = function () {
if (!this.offscreenGroup) {
var GroupCtor = this.container.getGroupBase(); // 获取分组的构造函数
this.offscreenGroup = new GroupCtor({});
}
return this.offscreenGroup;
};
// 对数据进行排序
Geometry.prototype.sort = function (mappingArray) {
if (!this.hasSorted) {
// 未发生过排序
var xScale_1 = this.getXScale();
var xField_1 = xScale_1.field;
for (var index = 0; index < mappingArray.length; index++) {
var itemArr = mappingArray[index];
itemArr.sort(function (obj1, obj2) {
return xScale_1.translate(obj1[FIELD_ORIGIN][xField_1]) - xScale_1.translate(obj2[FIELD_ORIGIN][xField_1]);
});
}
;
}
this.hasSorted = true;
};
/**
* 调整度量范围主要针对发生层叠以及一些特殊需求的 Geometry比如 Interval 下的柱状图 Y 轴默认从 0 开始
*/
Geometry.prototype.adjustScale = function () {
var yScale = this.getYScale();
// 如果数据发生过 stack adjust需要调整下 yScale 的数据范围
if (yScale && this.getAdjust('stack')) {
this.updateStackRange(yScale, this.beforeMappingData);
}
};
/**
* 获取当前 Geometry 对应的 Shape 工厂实例
*/
Geometry.prototype.getShapeFactory = function () {
var shapeType = this.shapeType;
if (!getShapeFactory(shapeType)) {
return;
}
if (!this.shapeFactory) {
this.shapeFactory = clone(getShapeFactory(shapeType)); // 防止多个 view 共享一个 shapeFactory 实例,导致 coordinate 被篡改
}
// 因为这里缓存了 shapeFactory但是外部可能会变更 coordinate导致无法重新设置到 shapeFactory 中
this.shapeFactory.coordinate = this.coordinate;
// theme 原因同上
this.shapeFactory.theme = this.theme.geometries[shapeType] || {};
return this.shapeFactory;
};
/**
* 获取每个 Shape 对应的关键点数据
* @param obj 经过分组 -> 数字化 -> adjust 调整后的数据记录
* @returns
*/
Geometry.prototype.createShapePointsCfg = function (obj) {
var xScale = this.getXScale();
var yScale = this.getYScale();
var x = this.normalizeValues(obj[xScale.field], xScale);
var y; // 存在没有 y 的情况
if (yScale) {
y = this.normalizeValues(obj[yScale.field], yScale);
}
else {
y = obj.y ? obj.y : 0.1;
}
return {
x: x,
y: y,
y0: yScale ? yScale.scale(this.getYMinValue()) : undefined,
};
};
/**
* 创建 Element 实例
* @param mappingDatum Element 对应的绘制数据
* @param [isUpdate] 是否处于更新阶段
* @returns element 返回创建的 Element 实例
*/
Geometry.prototype.createElement = function (mappingDatum, isUpdate) {
if (isUpdate === void 0) { isUpdate = false; }
var container = this.container;
var shapeCfg = this.getDrawCfg(mappingDatum); // 获取绘制图形的配置信息
var shapeFactory = this.getShapeFactory();
var element = new Element({
shapeFactory: shapeFactory,
container: container,
offscreenGroup: this.getOffscreenGroup(),
});
element.animate = this.animateOption;
element.geometry = this;
element.draw(shapeCfg, isUpdate); // 绘制
return element;
};
/**
* 获取每条数据对应的图形绘制数据
* @param mappingDatum 映射后的数据
* @returns draw cfg
*/
Geometry.prototype.getDrawCfg = function (mappingDatum) {
var originData = mappingDatum[FIELD_ORIGIN]; // 原始数据
var cfg = {
mappingData: mappingDatum,
data: originData,
x: mappingDatum.x,
y: mappingDatum.y,
color: mappingDatum.color,
size: mappingDatum.size,
isInCircle: this.coordinate.isPolar,
};
var shapeName = mappingDatum.shape;
if (!shapeName && this.getShapeFactory()) {
shapeName = this.getShapeFactory().defaultShapeType;
}
cfg.shape = shapeName;
// 获取默认样式
var theme = this.theme.geometries[this.shapeType];
cfg.defaultStyle = get(theme, [shapeName, 'default'], {}).style;
var styleOption = this.styleOption;
if (styleOption) {
cfg.style = this.getStyleCfg(styleOption, originData);
}
if (this.generatePoints) {
cfg.points = mappingDatum.points;
cfg.nextPoints = mappingDatum.nextPoints;
}
return cfg;
};
/**
* 创建所有的 Elements
* @param mappingData
* @param [isUpdate]
* @returns elements
*/
Geometry.prototype.createElements = function (mappingData, index, isUpdate) {
if (isUpdate === void 0) { isUpdate = false; }
var _a = this, lastElementsMap = _a.lastElementsMap, elementsMap = _a.elementsMap, elements = _a.elements;
for (var subIndex = 0, length_6 = mappingData.length; subIndex < length_6; subIndex++) {
var mappingDatum = mappingData[subIndex];
var id = this.getElementId(mappingDatum);
if (elementsMap[id]) {
// 存在重复数据,则根据再根据 index 进行区分
id = id + "-" + index + "-" + subIndex;
}
var result = lastElementsMap[id];
if (!result) {
// 创建新的 element
result = this.createElement(mappingDatum, isUpdate);
}
else {
// element 已经创建
var currentShapeCfg = this.getDrawCfg(mappingDatum);
var preShapeCfg = result.getModel();
if (this.isCoordinateChanged || isModelChange(currentShapeCfg, preShapeCfg)) {
result.animate = this.animateOption;
// 通过绘制数据的变更来判断是否需要更新,因为用户有可能会修改图形属性映射
result.update(currentShapeCfg); // 更新对应的 element
}
delete lastElementsMap[id];
}
elements.push(result);
elementsMap[id] = result;
}
return elements;
};
/**
* 获取渲染的 label 类型
*/
Geometry.prototype.getLabelType = function () {
var _a = this, labelOption = _a.labelOption, coordinate = _a.coordinate, type = _a.type;
var coordinateType = coordinate.type;
var labelType = get(labelOption, ['cfg', 'type']);
if (!labelType) {
// 用户未定义,则进行默认的逻辑
if (coordinateType === 'polar') {
// 极坐标下使用通用的极坐标文本
labelType = 'polar';
}
else if (coordinateType === 'theta') {
// theta 坐标系下使用饼图文本
labelType = 'pie';
}
else if (type === 'interval' || type === 'polygon') {
labelType = 'interval';
}
else {
labelType = 'base';
}
}
return labelType;
};
/**
* 获取 Y 轴上的最小值
*/
Geometry.prototype.getYMinValue = function () {
var yScale = this.getYScale();
var min = yScale.min, max = yScale.max;
var value;
if (min >= 0) {
value = min;
}
else if (max <= 0) {
// 当值全位于负区间时,需要保证 ymin 在区域内,不可为 0
value = max;
}
else {
value = 0;
}
return value;
};
// 创建图形属性相关的配置项
Geometry.prototype.createAttrOption = function (attrName, field, cfg) {
if (isNil(field) || isObject(field)) {
if (isObject(field) && isEqual(Object.keys(field), ['values'])) {
// shape({ values: [ 'funnel' ] })
set(this.attributeOption, attrName, {
fields: field.values,
});
}
else {
set(this.attributeOption, attrName, field);
}
}
else {
var attrCfg = {};
if (isNumber(field)) {
// size(3)
attrCfg.values = [field];
}
else {
attrCfg.fields = parseFields(field);
}
if (cfg) {
if (isFunction(cfg)) {
attrCfg.callback = cfg;
}
else {
attrCfg.values = cfg;
}
}
set(this.attributeOption, attrName, attrCfg);
}
};
Geometry.prototype.initAttributes = function () {
var _this = this;
var _a = this, attributes = _a.attributes, attributeOption = _a.attributeOption, theme = _a.theme, shapeType = _a.shapeType;
this.groupScales = [];
var tmpMap = {};
var _loop_1 = function (attrType) {
if (attributeOption.hasOwnProperty(attrType)) {
var option = attributeOption[attrType];
if (!option) {
return { value: void 0 };
}
var attrCfg = __assign({}, option);
var callback = attrCfg.callback, values = attrCfg.values, _a = attrCfg.fields, fields = _a === void 0 ? [] : _a;
// 获取每一个字段对应的 scale
var scales = fields.map(function (field) {
var scale = _this.scales[field];
if (scale.isCategory && !tmpMap[field] && GROUP_ATTRS.includes(attrType)) {
_this.groupScales.push(scale);
tmpMap[field] = true;
}
return scale;
});
attrCfg.scales = scales;
if (attrType !== 'position' && scales.length === 1 && scales[0].type === 'identity') {
// 用户在图形通道上声明了常量字段 color('red'), size(5)
attrCfg.values = scales[0].values;
}
else if (!callback && !values) {
// 用户没有指定任何规则,则使用默认的映射规则
if (attrType === 'size') {
attrCfg.values = theme.sizes;
}
else if (attrType === 'shape') {
attrCfg.values = theme.shapes[shapeType] || [];
}
else if (attrType === 'color') {
if (scales.length) {
// 根据数值个数使用对应的色板
attrCfg.values = scales[0].values.length <= 10 ? theme.colors10 : theme.colors20;
}
else {
attrCfg.values = theme.colors10;
}
}
}
var AttributeCtor = getAttributeClass(attrType);
attributes[attrType] = new AttributeCtor(attrCfg);
}
};
// 遍历每一个 attrOption各自创建 Attribute 实例
for (var attrType in attributeOption) {
var state_1 = _loop_1(attrType);
if (typeof state_1 === "object")
return state_1.value;
}
};
// 处理数据:分组 -> 数字化 -> adjust 调整
Geometry.prototype.processData = function (data) {
this.hasSorted = false;
var scales = this.getAttribute('position').scales;
var categoryScales = scales.filter(function (scale) { return scale.isCategory; });
var groupedArray = this.groupData(data); // 数据分组
var beforeAdjust = [];
for (var i = 0, len = groupedArray.length; i < len; i++) {
var subData = groupedArray[i];
var arr = [];
for (var j = 0, subLen = subData.length; j < subLen; j++) {
var originData = subData[j];
var item = {};
// tslint:disable-next-line: forin
for (var k in originData) {
item[k] = originData[k];
}
item[FIELD_ORIGIN] = originData;
// 将分类数据翻译成数据, 仅对位置相关的度量进行数字化处理
for (var _i = 0, categoryScales_1 = categoryScales; _i < categoryScales_1.length; _i++) {
var scale = categoryScales_1[_i];
var field = scale.field;
item[field] = scale.translate(item[field]);
}
arr.push(item);
}
beforeAdjust.push(arr);
}
var dataArray = this.adjustData(beforeAdjust); // 进行 adjust 数据调整
this.beforeMappingData = dataArray;
return dataArray;
};
// 调整数据
Geometry.prototype.adjustData = function (dataArray) {
var adjustOption = this.adjustOption;
var result = dataArray;
if (adjustOption) {
var xScale = this.getXScale();
var yScale = this.getYScale();
var xField = xScale.field;
var yField = yScale ? yScale.field : null;
for (var i = 0, len = adjustOption.length; i < len; i++) {
var adjust = adjustOption[i];
var adjustCfg = __assign({ xField: xField,
yField: yField }, adjust);
var type = adjust.type;
if (type === 'dodge') {
var adjustNames = [];
if (xScale.isCategory || xScale.type === 'identity') {
adjustNames.push('x');
}
else if (!yScale) {
adjustNames.push('y');
}
else {
throw new Error('dodge is not support linear attribute, please use category attribute!');
}
adjustCfg.adjustNames = adjustNames;
// 每个分组内每条柱子的宽度占比,用户不可指定,用户需要通过 columnWidthRatio 指定
adjustCfg.dodgeRatio = this.theme.columnWidthRatio;
}
else if (type === 'stack') {
var coordinate = this.coordinate;
if (!yScale) {
// 一维的情况下获取高度和默认size
adjustCfg.height = coordinate.getHeight();
var size = this.getDefaultValue('size') || 3;
adjustCfg.size = size;
}
// 不进行 transpose 时,用户又没有设置这个参数时,默认从上向下
if (!coordinate.isTransposed && isNil(adjustCfg.reverseOrder)) {
adjustCfg.reverseOrder = true;
}
}
var adjustCtor = getAdjustClass(type);
var adjustInstance = new adjustCtor(adjustCfg);
result = adjustInstance.process(result);
this.adjusts[type] = adjustInstance;
}
}
return result;
};
// 对数据进行分组
Geometry.prototype.groupData = function (data) {
var groupScales = this.getGroupScales();
var scaleDefs = this.scaleDefs;
var appendConditions = {};
var groupFields = [];
for (var index = 0; index < groupScales.length; index++) {
var scale = groupScales[index];
var field = scale.field;
groupFields.push(field);
if (get(scaleDefs, [field, 'values'])) {
// 用户通过 view.scale() 接口指定了 values 属性
appendConditions[field] = scaleDefs[field].values;
}
}
return group(data, groupFields, appendConditions);
};
// 更新发生层叠后的数据对应的度量范围
Geometry.prototype.updateStackRange = function (scale, dataArray) {
var mergeArray = flatten(dataArray);
var field = scale.field;
var min = scale.min;
var max = scale.max;
for (var index = 0; index < mergeArray.length; index++) {
var obj = mergeArray[index];
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;
}
}
var scaleDefs = this.scaleDefs;
var cfg = {};
if ((min < scale.min) && !get(scaleDefs, [field, 'min'])) {
// 用户如果在列定义中定义了 min则以用户定义的为准
cfg.min = min;
}
if ((max > scale.max) && !get(scaleDefs, [field, 'max'])) {
// 用户如果在列定义中定义了 max
cfg.max = max;
}
scale.change(cfg);
};
// 将数据映射至图形空间前的操作:排序以及关键点的生成
Geometry.prototype.beforeMapping = function (beforeMappingData) {
// 当初加 clone 是因为 points 的引用关系,导致更新失败,可是现在貌似复现不出来了,所以暂时不进行 clone
// const source = clone(beforeMappingData);
var source = beforeMappingData;
if (this.sortable) {
this.sort(source);
}
if (this.generatePoints) {
// 需要生成关键点
for (var index = 0, length_7 = source.length; index < length_7; index++) {
var currentData = source[index];
this.generateShapePoints(currentData);
var nextData = source[index + 1];
if (nextData) {
this.generateShapePoints(nextData);
currentData[0].nextPoints = nextData[0].points;
}
}
}
return source;
};
// 生成 shape 的关键点
Geometry.prototype.generateShapePoints = function (data) {
var shapeFactory = this.getShapeFactory();
var shapeAttr = this.getAttribute('shape');
for (var index = 0; index < data.length; index++) {
var obj = data[index];
var cfg = this.createShapePointsCfg(obj);
var shape = shapeAttr ? this.getAttributeValues(shapeAttr, obj) : null;
var points = shapeFactory.getShapePoints(shape, cfg);
obj.points = points;
}
};
// 将数据归一化
Geometry.prototype.normalizeValues = function (values, scale) {
var rst = [];
if (isArray(values)) {
for (var index = 0; index < values.length; index++) {
var value = values[index];
rst.push(scale.scale(value));
}
}
else {
rst = scale.scale(values);
}
return rst;
};
// 将数据映射至图形空间
Geometry.prototype.mapping = function (data) {
var attributes = this.attributes;
var mappingData = [];
for (var index = 0; index < data.length; index++) {
var record = data[index];
var newRecord = {
_origin: record[FIELD_ORIGIN],
points: record.points,
nextPoints: record.nextPoints,
};
for (var k in attributes) {
if (attributes.hasOwnProperty(k)) {
var attr = attributes[k];
var names = attr.names;
var values = this.getAttributeValues(attr, record);
if (names.length > 1) {
// position 之类的生成多个字段的属性
for (var j = 0; j < values.length; j += 1) {
var val = values[j];
var name_1 = names[j];
newRecord[name_1] = isArray(val) && val.length === 1 ? val[0] : val; // 只有一个值时返回第一个属性值
}
}
else {
// values.length === 1 的判断是以下情况,获取用户设置的图形属性值
// shape('a', ['dot', 'dash']), color('a', ['red', 'yellow'])
newRecord[names[0]] = values.length === 1 ? values[0] : values;
}
}
}
this.convertPoint(newRecord); // 将 x、y 转换成画布坐标
mappingData.push(newRecord);
}
return mappingData;
};
// 将归一化的坐标值转换成画布坐标
Geometry.prototype.convertPoint = function (mappingRecord) {
var x = mappingRecord.x, y = mappingRecord.y;
var rstX;
var rstY;
var obj;
var coordinate = this.coordinate;
if (isArray(x) && isArray(y)) {
rstX = [];
rstY = [];
for (var i = 0, j = 0, xLen = x.length, yLen = y.length; i < xLen && j < yLen; i += 1, j += 1) {
obj = coordinate.convert({
x: x[i],
y: y[j],
});
rstX.push(obj.x);
rstY.push(obj.y);
}
}
else if (isArray(y)) {
rstY = [];
for (var index = 0; index < y.length; index++) {
var yVal = y[index];
obj = coordinate.convert({
x: x,
y: yVal,
});
if (rstX && rstX !== obj.x) {
if (!isArray(rstX)) {
rstX = [rstX];
}
rstX.push(obj.x);
}
else {
rstX = obj.x;
}
rstY.push(obj.y);
}
}
else if (isArray(x)) {
rstX = [];
for (var index = 0; index < x.length; index++) {
var xVal = x[index];
obj = coordinate.convert({
x: xVal,
y: y,
});
if (rstY && rstY !== obj.y) {
if (!isArray(rstY)) {
rstY = [rstY];
}
rstY.push(obj.y);
}
else {
rstY = obj.y;
}
rstX.push(obj.x);
}
}
else {
var point = coordinate.convert({
x: x,
y: y,
});
rstX = point.x;
rstY = point.y;
}
mappingRecord.x = rstX;
mappingRecord.y = rstY;
};
// 获取 style 配置
Geometry.prototype.getStyleCfg = function (styleOption, originData) {
var _a = styleOption.fields, fields = _a === void 0 ? [] : _a, callback = styleOption.callback, cfg = styleOption.cfg;
if (cfg) {
// 用户直接配置样式属性
return cfg;
}
var params = fields.map(function (field) {
return originData[field];
});
return callback.apply(void 0, params);
};
Geometry.prototype.setCfg = function (cfg) {
var _this = this;
var coordinate = cfg.coordinate, data = cfg.data, theme = cfg.theme, scaleDefs = cfg.scaleDefs;
if (coordinate) {
this.coordinate = coordinate;
}
if (data) {
this.data = data;
}
if (scaleDefs) {
this.scaleDefs = scaleDefs;
this.idFields = [];
each(scaleDefs, function (scaleDef, field) {
if (scaleDef && scaleDef.key) {
_this.idFields.push(field);
}
});
}
if (theme) {
this.theme = this.userTheme ? deepMix({}, theme, this.userTheme) : theme; // 支持 geometry 层级的主题设置
}
};
Geometry.prototype.renderLabels = function (mappingArray, isUpdate) {
if (isUpdate === void 0) { isUpdate = false; }
var geometryLabel = this.geometryLabel;
if (!geometryLabel) {
// 初次创建
var labelType = this.getLabelType();
var GeometryLabelsCtor = getGeometryLabel(labelType);
geometryLabel = new GeometryLabelsCtor(this);
this.geometryLabel = geometryLabel;
}
geometryLabel.render(mappingArray, isUpdate);
// 将 label 同 element 进行关联
var labelsMap = geometryLabel.labelsRenderer.shapesMap;
each(this.elementsMap, function (element, id) {
var labels = filterLabelsById(id, labelsMap); // element 实例同 label 进行绑定
if (labels.length) {
element.labelShape = labels;
for (var i = 0; i < labels.length; i++) {
var label = labels[i];
var labelChildren = label.getChildren();
for (var j = 0; j < labelChildren.length; j++) {
var child = labelChildren[j];
child.cfg.name = ['element', 'label'];
child.cfg.element = element;
}
}
}
});
};
/**
* 是否需要进行群组入场动画
* 规则
* 1. 如果发生更新则不进行
* 2. 如果用户关闭 geometry 动画则不进行
* 3. 如果用户关闭了 appear 动画则不进行
* 4. 如果用户配置了 appear.animation则不进行
*/
Geometry.prototype.canDoGroupAnimation = function (isUpdate) {
return (!isUpdate &&
this.animateOption &&
(get(this.animateOption, 'appear') === undefined ||
(get(this.animateOption, 'appear') && get(this.animateOption, ['appear', 'animation']) === undefined)));
};
return Geometry;
}(Base));
export default Geometry;
//# sourceMappingURL=base.js.map