NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/esm/geometry/base.js
2023-09-14 14:47:11 +08:00

1346 lines
49 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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