NuclearDispersionSystem/ant-design-vue-jeecg/node_modules/@antv/g2/esm/chart/controller/legend.js

497 lines
18 KiB
Java
Raw Normal View History

2023-09-14 14:47:11 +08:00
import { __extends } from "tslib";
import { deepMix, each, find, get, head, isBoolean, last } from '@antv/util';
import { COMPONENT_MAX_VIEW_PERCENTAGE, COMPONENT_TYPE, DIRECTION, LAYER } from '../../constant';
import { CategoryLegend, ContinuousLegend } from '../../dependents';
import { DEFAULT_ANIMATE_CFG } from '../../animate';
import { BBox } from '../../util/bbox';
import { directionToPosition } from '../../util/direction';
import { omit } from '../../util/helper';
import { getCustomLegendItems, getLegendItems, getLegendLayout } from '../../util/legend';
import { getName } from '../../util/scale';
import { Controller } from './base';
/**
* 从配置中获取单个字段的 legend 配置
* @param legends
* @param field
* @returns the option of one legend field
*/
function getLegendOption(legends, field) {
if (isBoolean(legends)) {
return legends === false ? false : {};
}
return get(legends, [field], legends);
}
function getDirection(legendOption) {
return get(legendOption, 'position', DIRECTION.BOTTOM);
}
/**
* @ignore
* legend Controller
*/
var Legend = /** @class */ (function (_super) {
__extends(Legend, _super);
function Legend(view) {
var _this = _super.call(this, view) || this;
_this.container = _this.view.getLayer(LAYER.FORE).addGroup();
return _this;
}
Object.defineProperty(Legend.prototype, "name", {
get: function () {
return 'legend';
},
enumerable: false,
configurable: true
});
Legend.prototype.init = function () { };
/**
* render the legend component by legend options
*/
Legend.prototype.render = function () {
var _this = this;
this.option = this.view.getOptions().legends;
var doEachLegend = function (geometry, attr, scale) {
var legend = _this.createFieldLegend(geometry, attr, scale);
if (legend) {
legend.component.init();
_this.components.push(legend);
}
};
// 全局自定义图例
if (get(this.option, 'custom')) {
var component = this.createCustomLegend(undefined, undefined, undefined, this.option);
if (component) {
component.init();
var layer = LAYER.FORE;
var direction = getDirection(this.option);
this.components.push({
id: 'global-custom',
component: component,
layer: layer,
direction: direction,
type: COMPONENT_TYPE.LEGEND,
extra: undefined,
});
}
}
else {
// 遍历处理每一个创建逻辑
this.loopLegends(doEachLegend);
}
};
/**
* layout legend
* 计算出 legend direction 位置 x, y
*/
Legend.prototype.layout = function () {
var _this = this;
this.layoutBBox = this.view.viewBBox;
each(this.components, function (co) {
var component = co.component, direction = co.direction;
var layout = getLegendLayout(direction);
var maxSize = _this.getCategoryLegendSizeCfg(layout);
var maxWidth = component.get('maxWidth');
var maxHeight = component.get('maxHeight');
// 先更新 maxSize更新 layoutBBox以便计算正确的 x y
component.update({
maxWidth: Math.min(maxSize.maxWidth, maxWidth || 0),
maxHeight: Math.min(maxSize.maxHeight, maxHeight || 0),
});
var bboxObject = component.getLayoutBBox(); // 这里只需要他的 width、height 信息做位置调整
var bbox = new BBox(bboxObject.x, bboxObject.y, bboxObject.width, bboxObject.height);
var _a = directionToPosition(_this.view.coordinateBBox, bbox, direction), x1 = _a[0], y1 = _a[1];
var _b = directionToPosition(_this.layoutBBox, bbox, direction), x2 = _b[0], y2 = _b[1];
var x = 0;
var y = 0;
// 因为 legend x y 要和 coordinateBBox 对齐,所以要做一个简单的判断
if (direction.startsWith('top') || direction.startsWith('bottom')) {
x = x1;
y = y2;
}
else {
x = x2;
y = y1;
}
// 更新位置
component.update({
x: x,
y: y,
});
_this.layoutBBox = _this.layoutBBox.cut(bbox, direction);
});
};
/**
* legend 的更新逻辑
*/
Legend.prototype.update = function () {
var _this = this;
this.option = this.view.getOptions().legends;
// 已经处理过的 legend
var updated = {};
var eachLegend = function (geometry, attr, scale) {
var id = _this.getId(scale.field);
var existCo = _this.getComponentById(id);
// 存在则 update
if (existCo) {
var cfg = void 0;
var legendOption = getLegendOption(_this.option, scale.field);
// if the legend option is not false, means legend should be created.
if (legendOption !== false) {
if (get(legendOption, 'custom')) {
cfg = _this.getCategoryCfg(geometry, attr, scale, legendOption, true);
}
else {
if (scale.isLinear) {
// linear field, create continuous legend
cfg = _this.getContinuousCfg(geometry, attr, scale, legendOption);
}
else if (scale.isCategory) {
// category field, create category legend
cfg = _this.getCategoryCfg(geometry, attr, scale, legendOption);
}
}
}
// 如果 cfg 为空,则不在 updated 标记,那么会在后面逻辑中删除
if (cfg) {
// omit 掉一些属性,比如 container 等
omit(cfg, ['container']);
existCo.direction = getDirection(legendOption);
existCo.component.update(cfg);
// 标记为新的
updated[id] = true;
}
}
else {
// 不存在则 create
var legend = _this.createFieldLegend(geometry, attr, scale);
if (legend) {
legend.component.init();
_this.components.push(legend);
// 标记为新的
updated[id] = true;
}
}
};
// 全局自定义图例
if (get(this.option, 'custom')) {
var id = 'global-custom';
var existCo = this.getComponentById(id);
if (existCo) {
var customCfg = this.getCategoryCfg(undefined, undefined, undefined, this.option, true);
omit(customCfg, ['container']);
existCo.component.update(customCfg);
updated[id] = true;
}
else {
var component = this.createCustomLegend(undefined, undefined, undefined, this.option);
if (component) {
component.init();
var layer = LAYER.FORE;
var direction = getDirection(this.option);
this.components.push({
id: id,
component: component,
layer: layer,
direction: direction,
type: COMPONENT_TYPE.LEGEND,
extra: undefined,
});
// 标记为更新
updated[id] = true;
}
}
}
else {
// 遍历处理每一个创建逻辑
this.loopLegends(eachLegend);
}
// 处理完成之后,销毁删除的
// 不在处理中的
var components = [];
each(this.getComponents(), function (co) {
if (updated[co.id]) {
components.push(co);
}
else {
co.component.destroy();
}
});
// 更新当前已有的 components
this.components = components;
};
Legend.prototype.clear = function () {
_super.prototype.clear.call(this);
this.container.clear();
};
Legend.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.container.remove(true);
};
/**
* 递归获取所有的 Geometry
*/
Legend.prototype.getGeometries = function (view) {
var _this = this;
var geometries = view.geometries;
each(view.views, function (v) {
geometries = geometries.concat(_this.getGeometries(v));
});
return geometries;
};
/**
* 遍历 Geometry处理 legend 逻辑
* @param doEach 每个 loop 中的处理方法
*/
Legend.prototype.loopLegends = function (doEach) {
var isRootView = this.view.getRootView() === this.view;
// 非根 view不处理 legend
if (!isRootView) {
return;
}
// 递归 view 中所有的 Geometry进行创建 legend
var geometries = this.getGeometries(this.view);
var looped = {}; // 防止一个字段创建两个 legend
each(geometries, function (geometry) {
var attributes = geometry.getGroupAttributes();
each(attributes, function (attr) {
var scale = attr.getScale(attr.type);
// 如果在视觉通道上映射常量值,如 size(2) shape('circle') 不创建 legend
if (!scale || scale.type === 'identity' || looped[scale.field]) {
return;
}
doEach(geometry, attr, scale);
looped[scale.field] = true;
});
});
};
/**
* 创建一个 legend
* @param geometry
* @param attr
* @param scale
*/
Legend.prototype.createFieldLegend = function (geometry, attr, scale) {
var component;
var legendOption = getLegendOption(this.option, scale.field);
var layer = LAYER.FORE;
var direction = getDirection(legendOption);
// if the legend option is not false, means legend should be created.
if (legendOption !== false) {
if (get(legendOption, 'custom')) {
component = this.createCustomLegend(geometry, attr, scale, legendOption);
}
else {
if (scale.isLinear) {
// linear field, create continuous legend
component = this.createContinuousLegend(geometry, attr, scale, legendOption);
}
else if (scale.isCategory) {
// category field, create category legend
component = this.createCategoryLegend(geometry, attr, scale, legendOption);
}
}
}
if (component) {
component.set('field', scale.field);
return {
id: this.getId(scale.field),
component: component,
layer: layer,
direction: direction,
type: COMPONENT_TYPE.LEGEND,
extra: { scale: scale },
};
}
};
/**
* 自定义图例使用 category 图例去渲染
* @param geometry
* @param attr
* @param scale
* @param legendOption
*/
Legend.prototype.createCustomLegend = function (geometry, attr, scale, legendOption) {
// 直接使用 分类图例渲染
var cfg = this.getCategoryCfg(geometry, attr, scale, legendOption, true);
return new CategoryLegend(cfg);
};
/**
* 创建连续图例
* @param geometry
* @param attr
* @param scale
* @param legendOption
*/
Legend.prototype.createContinuousLegend = function (geometry, attr, scale, legendOption) {
var cfg = this.getContinuousCfg(geometry, attr, scale, legendOption);
return new ContinuousLegend(cfg);
};
/**
* 创建分类图例
* @param geometry
* @param attr
* @param scale
* @param legendOption
*/
Legend.prototype.createCategoryLegend = function (geometry, attr, scale, legendOption) {
var cfg = this.getCategoryCfg(geometry, attr, scale, legendOption);
return new CategoryLegend(cfg);
};
/**
* 获得连续图例的配置
* @param geometry
* @param attr
* @param scale
* @param legendOption
*/
Legend.prototype.getContinuousCfg = function (geometry, attr, scale, legendOption) {
var ticks = scale.getTicks();
var containMin = find(ticks, function (tick) { return tick.value === 0; });
var containMax = find(ticks, function (tick) { return tick.value === 1; });
var items = ticks.map(function (tick) {
var value = tick.value, tickValue = tick.tickValue;
var attrValue = attr.mapping(scale.invert(value)).join('');
return {
value: tickValue,
attrValue: attrValue,
color: attrValue,
scaleValue: value,
};
});
if (!containMin) {
items.push({
value: scale.min,
attrValue: attr.mapping(scale.invert(0)).join(''),
color: attr.mapping(scale.invert(0)).join(''),
scaleValue: 0,
});
}
if (!containMax) {
items.push({
value: scale.max,
attrValue: attr.mapping(scale.invert(1)).join(''),
color: attr.mapping(scale.invert(1)).join(''),
scaleValue: 1,
});
}
// 排序
items.sort(function (a, b) { return a.value - b.value; });
// 跟 attr 相关的配置
// size color 区别的配置
var attrLegendCfg = {
min: head(items).value,
max: last(items).value,
colors: [],
rail: {
type: attr.type,
},
track: {},
};
if (attr.type === 'size') {
attrLegendCfg.track = {
style: {
// size 的选中前景色,对于 color则直接使用 color 标识
// @ts-ignore
fill: attr.type === 'size' ? this.view.getTheme().defaultColor : undefined,
},
};
}
if (attr.type === 'color') {
attrLegendCfg.colors = items.map(function (item) { return item.attrValue; });
}
var container = this.container;
// if position is not set, use top as default
var direction = getDirection(legendOption);
var layout = getLegendLayout(direction);
var title = get(legendOption, 'title');
if (title) {
title = deepMix({
text: getName(scale),
}, title);
}
// 基础配置,从当前数据中读到的配置
attrLegendCfg.container = container;
attrLegendCfg.layout = layout;
attrLegendCfg.title = title;
attrLegendCfg.animateOption = DEFAULT_ANIMATE_CFG;
// @ts-ignore
return this.mergeLegendCfg(attrLegendCfg, legendOption, 'continuous');
};
/**
* 获取分类图例的配置项
* @param geometry
* @param attr
* @param scale
* @param custom
* @param legendOption
*/
Legend.prototype.getCategoryCfg = function (geometry, attr, scale, legendOption, custom) {
var container = this.container;
// if position is not set, use top as default
var direction = get(legendOption, 'position', DIRECTION.BOTTOM);
// the default marker style
var themeMarker = get(this.view.getTheme(), ['components', 'legend', direction, 'marker']);
var userMarker = get(legendOption, 'marker');
var layout = getLegendLayout(direction);
var items = custom ?
getCustomLegendItems(themeMarker, userMarker, legendOption.items) :
getLegendItems(this.view, geometry, attr, themeMarker, userMarker);
var title = get(legendOption, 'title');
if (title) {
title = deepMix({
text: scale ? getName(scale) : '',
}, title);
}
var baseCfg = this.getCategoryLegendSizeCfg(layout);
baseCfg.container = container;
baseCfg.layout = layout;
baseCfg.items = items;
baseCfg.title = title;
baseCfg.animateOption = DEFAULT_ANIMATE_CFG;
var categoryCfg = this.mergeLegendCfg(baseCfg, legendOption, direction);
if (categoryCfg.reversed) {
// 图例项需要逆序
categoryCfg.items.reverse();
}
return categoryCfg;
};
/**
* get legend config, use option > suggestion > theme
* @param baseCfg
* @param legendOption
* @param direction
*/
Legend.prototype.mergeLegendCfg = function (baseCfg, legendOption, direction) {
var themeObject = get(this.view.getTheme(), ['components', 'legend', direction], {});
return deepMix({}, themeObject, baseCfg, legendOption);
};
/**
* 生成 id
* @param key
*/
Legend.prototype.getId = function (key) {
return this.name + "-" + key;
};
/**
* 根据 id 来获取组件
* @param id
*/
Legend.prototype.getComponentById = function (id) {
return find(this.components, function (co) { return co.id === id; });
};
Legend.prototype.getCategoryLegendSizeCfg = function (layout) {
var _a = this.view.viewBBox, vw = _a.width, vh = _a.height;
var _b = this.view.coordinateBBox, cw = _b.width, ch = _b.height;
return layout === 'vertical'
? {
maxWidth: vw * COMPONENT_MAX_VIEW_PERCENTAGE,
maxHeight: ch,
}
: {
maxWidth: cw,
maxHeight: vh * COMPONENT_MAX_VIEW_PERCENTAGE,
};
};
return Legend;
}(Controller));
export default Legend;
//# sourceMappingURL=legend.js.map