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 结构存储 Element,key 为每个 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