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

555 lines
20 KiB
Java
Raw Normal View History

2023-09-14 14:47:11 +08:00
import { __assign, __extends } from "tslib";
import { contains, deepMix, each, get, isArray, isFunction, isNil, isString, keys, upperFirst } from '@antv/util';
import { Annotation as AnnotationComponent } from '../../dependents';
import { DEFAULT_ANIMATE_CFG } from '../../animate/';
import { COMPONENT_TYPE, DIRECTION, LAYER, VIEW_LIFE_CIRCLE } from '../../constant';
import { getAngleByPoint, getDistanceToCenter } from '../../util/coordinate';
import { omit } from '../../util/helper';
import { Controller } from './base';
/**
* Annotation controller, 主要作用:
* 1. 创建 Annotation: linetextarc ...
* 2. 生命周期: initlayoutrendercleardestroy
*/
var Annotation = /** @class */ (function (_super) {
__extends(Annotation, _super);
function Annotation(view) {
var _this = _super.call(this, view) || this;
/* 组件更新的 cache组件配置 object : 组件 */
_this.cache = new Map();
_this.foregroundContainer = _this.view.getLayer(LAYER.FORE).addGroup();
_this.backgroundContainer = _this.view.getLayer(LAYER.BG).addGroup();
_this.option = [];
return _this;
}
Object.defineProperty(Annotation.prototype, "name", {
get: function () {
return 'annotation';
},
enumerable: false,
configurable: true
});
Annotation.prototype.init = function () { };
Annotation.prototype.layout = function () {
var _this = this;
var components = this.getComponents();
var updateComponentFn = function (co) {
var component = co.component, extra = co.extra;
var type = extra.type;
var theme = _this.getAnnotationTheme(type);
component.update(_this.getAnnotationCfg(type, extra, theme));
};
var createComponentFn = function (option) {
var co = _this.createAnnotation(option);
if (co) {
co.component.init();
// NoteregionFilter 特殊处理regionFilter需要取到 Geometry 中的 Shape需要在 view render 之后处理
// 其他组件使用外层的统一 render 逻辑
if (option.type === 'regionFilter') {
co.component.render();
}
// 缓存起来
_this.cache.set(option, co);
}
};
if (components.length) {
each(components, function (co) {
var component = co.component;
if (component.get('type') === 'regionFilter') {
// regionFilter 依赖绘制后的 Geometry Shapes
_this.view.once(VIEW_LIFE_CIRCLE.AFTER_RENDER, function () {
updateComponentFn(co);
});
}
else {
updateComponentFn(co);
}
});
}
else {
each(this.option, function (option) {
if (option.type === 'regionFilter') {
_this.view.once(VIEW_LIFE_CIRCLE.AFTER_RENDER, function () {
// regionFilter 依赖绘制后的 Geometry Shapes
createComponentFn(option);
});
}
else {
createComponentFn(option);
}
});
}
};
Annotation.prototype.render = function () {
// 因为 Annotation 不参与布局,但是渲染的位置依赖于坐标系,所以可以将绘制阶段延迟到 layout() 进行
};
/**
* 更新
*/
Annotation.prototype.update = function () {
var _this = this;
// 已经处理过的 legend
var updated = new WeakMap();
var updateComponentFn = function (option) {
var type = option.type;
var theme = _this.getAnnotationTheme(type);
var cfg = _this.getAnnotationCfg(type, option, theme);
var existCo = _this.cache.get(option);
// 存在,则更新
if (existCo) {
// 忽略掉一些配置
omit(cfg, ['container']);
existCo.component.update(cfg);
updated.set(option, true);
}
else {
// 不存在,则创建
var co = _this.createAnnotation(option);
if (co) {
co.component.init();
// NoteregionFilter 特殊处理regionFilter需要取到 Geometry 中的 Shape需要在 view render 之后处理
// 其他组件使用外层的统一 render 逻辑
if (option.type === 'regionFilter') {
co.component.render();
}
// 缓存起来
_this.cache.set(option, co);
updated.set(option, true);
}
}
};
this.view.once(VIEW_LIFE_CIRCLE.AFTER_RENDER, function () {
// 先看是否有 regionFilter 要更新
each(_this.option, function (option) {
if (option.type === 'regionFilter') {
updateComponentFn(option);
}
});
// 处理完成之后,销毁删除的
// 不在处理中的
var newCache = new Map();
_this.cache.forEach(function (value, key) {
if (updated.has(key)) {
newCache.set(key, value);
}
else {
// 不存在,则是所有需要被销毁的组件
value.component.destroy();
}
});
// 更新缓存
_this.cache = newCache;
});
each(this.option, function (option) {
if (option.type !== 'regionFilter') {
updateComponentFn(option);
}
});
};
/**
* 清空
* @param includeOption 是否清空 option 配置项
*/
Annotation.prototype.clear = function (includeOption) {
if (includeOption === void 0) { includeOption = false; }
_super.prototype.clear.call(this);
this.cache.clear();
this.foregroundContainer.clear();
this.backgroundContainer.clear();
// clear all option
if (includeOption) {
this.option = [];
}
};
Annotation.prototype.destroy = function () {
this.clear(true);
this.foregroundContainer.remove(true);
this.backgroundContainer.remove(true);
};
/**
* 复写基类的方法
*/
Annotation.prototype.getComponents = function () {
var co = [];
this.cache.forEach(function (value) {
co.push(value);
});
return co;
};
Annotation.prototype.createAnnotation = function (option) {
var type = option.type;
var Ctor = AnnotationComponent[upperFirst(type)];
if (Ctor) {
var theme = this.getAnnotationTheme(type);
var cfg = this.getAnnotationCfg(type, option, theme);
var annotation = new Ctor(cfg);
return {
component: annotation,
layer: this.isTop(cfg) ? LAYER.FORE : LAYER.BG,
direction: DIRECTION.NONE,
type: COMPONENT_TYPE.ANNOTATION,
extra: option,
};
}
};
// APIs for creating annotation component
Annotation.prototype.annotation = function (option) {
this.option.push(option);
};
/**
* 创建 Arc
* @param option
* @returns AnnotationController
*/
Annotation.prototype.arc = function (option) {
this.annotation(__assign({ type: 'arc' }, option));
return this;
};
/**
* 创建 image
* @param option
* @returns AnnotationController
*/
Annotation.prototype.image = function (option) {
this.annotation(__assign({ type: 'image' }, option));
return this;
};
/**
* 创建 Line
* @param option
* @returns AnnotationController
*/
Annotation.prototype.line = function (option) {
this.annotation(__assign({ type: 'line' }, option));
return this;
};
/**
* 创建 Region
* @param option
* @returns AnnotationController
*/
Annotation.prototype.region = function (option) {
this.annotation(__assign({ type: 'region' }, option));
return this;
};
/**
* 创建 Text
* @param option
* @returns AnnotationController
*/
Annotation.prototype.text = function (option) {
this.annotation(__assign({ type: 'text' }, option));
return this;
};
/**
* 创建 DataMarker
* @param option
* @returns AnnotationController
*/
Annotation.prototype.dataMarker = function (option) {
this.annotation(__assign({ type: 'dataMarker' }, option));
return this;
};
/**
* 创建 DataRegion
* @param option
* @returns AnnotationController
*/
Annotation.prototype.dataRegion = function (option) {
this.annotation(__assign({ type: 'dataRegion' }, option));
};
/**
* 创建 RegionFilter
* @param option
* @returns AnnotationController
*/
Annotation.prototype.regionFilter = function (option) {
this.annotation(__assign({ type: 'regionFilter' }, option));
};
// end API
/**
* parse the point position to [x, y]
* @param p Position
* @returns { x, y }
*/
Annotation.prototype.parsePosition = function (p) {
var xScale = this.view.getXScale();
// 转成 object
var yScales = this.view.getScalesByDim('y');
var position = isFunction(p) ? p.call(null, xScale, yScales) : p;
var x = 0;
var y = 0;
// 入参是 [24, 24] 这类时
if (isArray(position)) {
var xPos = position[0], yPos = position[1];
// 如果数据格式是 ['50%', '50%'] 的格式
// fix: 原始数据中可能会包含 'xxx5%xxx' 这样的数据,需要判断下 https://github.com/antvis/f2/issues/590
// @ts-ignore
if (isString(xPos) && xPos.indexOf('%') !== -1 && !isNaN(xPos.slice(0, -1))) {
return this.parsePercentPosition(position);
}
x = this.getNormalizedValue(xPos, xScale);
y = this.getNormalizedValue(yPos, Object.values(yScales)[0]);
}
else if (!isNil(position)) {
// 入参是 object 结构,数据点
for (var _i = 0, _a = keys(position); _i < _a.length; _i++) {
var key = _a[_i];
var value = position[key];
if (key === xScale.field) {
x = this.getNormalizedValue(value, xScale);
}
if (yScales[key]) {
y = this.getNormalizedValue(value, yScales[key]);
}
}
}
return this.view.getCoordinate().convert({ x: x, y: y });
};
/**
* parse all the points between start and end
* @param start
* @param end
* @return Point[]
*/
Annotation.prototype.getRegionPoints = function (start, end) {
var _this = this;
var xScale = this.view.getXScale();
var yScales = this.view.getScalesByDim('y');
var yScale = Object.values(yScales)[0];
var xField = xScale.field;
var viewData = this.view.getData();
var startXValue = isArray(start) ? start[0] : start[xField];
var endXValue = isArray(end) ? end[0] : end[xField];
var arr = [];
var startIndex;
each(viewData, function (item, idx) {
if (item[xField] === startXValue) {
startIndex = idx;
}
if (idx >= startIndex) {
var point = _this.parsePosition([item[xField], item[yScale.field]]);
if (point) {
arr.push(point);
}
}
if (item[xField] === endXValue) {
return false;
}
});
return arr;
};
/**
* parse the value position
* @param val
* @param scale
*/
Annotation.prototype.getNormalizedValue = function (val, scale) {
var result;
var scaled;
switch (val) {
case 'start':
result = 0;
break;
case 'end':
result = 1;
break;
case 'median': {
scaled = scale.isCategory ? (scale.values.length - 1) / 2 : (scale.min + scale.max) / 2;
result = scale.scale(scaled);
break;
}
case 'min':
case 'max':
if (scale.isCategory) {
scaled = val === 'min' ? 0 : scale.values.length - 1;
}
else {
scaled = scale[val];
}
result = scale.scale(scaled);
break;
default:
result = scale.scale(val);
}
return result;
};
/**
* parse percent position
* @param position
*/
Annotation.prototype.parsePercentPosition = function (position) {
var xPercent = parseFloat(position[0]) / 100;
var yPercent = parseFloat(position[1]) / 100;
var coordinate = this.view.getCoordinate();
var start = coordinate.start, end = coordinate.end;
var topLeft = {
x: Math.min(start.x, end.x),
y: Math.min(start.y, end.y),
};
var x = coordinate.getWidth() * xPercent + topLeft.x;
var y = coordinate.getHeight() * yPercent + topLeft.y;
return { x: x, y: y };
};
/**
* get coordinate bbox
*/
Annotation.prototype.getCoordinateBBox = function () {
var coordinate = this.view.getCoordinate();
var start = coordinate.start, end = coordinate.end;
var width = coordinate.getWidth();
var height = coordinate.getHeight();
var topLeft = {
x: Math.min(start.x, end.x),
y: Math.min(start.y, end.y),
};
return {
x: topLeft.x,
y: topLeft.y,
minX: topLeft.x,
minY: topLeft.y,
maxX: topLeft.x + width,
maxY: topLeft.y + height,
width: width,
height: height,
};
};
/**
* get annotation component config by different type
* @param type
* @param option 用户的配置
* @param theme
*/
Annotation.prototype.getAnnotationCfg = function (type, option, theme) {
var coordinate = this.view.getCoordinate();
var o = {};
if (isNil(option)) {
return null;
}
if (type === 'arc') {
var _a = option, start = _a.start, end = _a.end;
var sp = this.parsePosition(start);
var ep = this.parsePosition(end);
var startAngle = getAngleByPoint(coordinate, sp);
var endAngle = getAngleByPoint(coordinate, ep);
if (startAngle > endAngle) {
endAngle = Math.PI * 2 + endAngle;
}
o = {
center: coordinate.getCenter(),
radius: getDistanceToCenter(coordinate, sp),
startAngle: startAngle,
endAngle: endAngle,
};
}
else if (type === 'image') {
var _b = option, start = _b.start, end = _b.end;
o = {
start: this.parsePosition(start),
end: this.parsePosition(end),
src: option.src,
};
}
else if (type === 'line') {
var _c = option, start = _c.start, end = _c.end;
o = {
start: this.parsePosition(start),
end: this.parsePosition(end),
text: get(option, 'text', null),
};
}
else if (type === 'region') {
var _d = option, start = _d.start, end = _d.end;
o = {
start: this.parsePosition(start),
end: this.parsePosition(end),
};
}
else if (type === 'text') {
var _e = option, position = _e.position, rotate = _e.rotate;
o = __assign(__assign({}, this.parsePosition(position)), { content: option.content, rotate: rotate });
}
else if (type === 'dataMarker') {
var _f = option, position = _f.position, point = _f.point, line = _f.line, text = _f.text, autoAdjust = _f.autoAdjust, direction = _f.direction;
o = __assign(__assign({}, this.parsePosition(position)), { coordinateBBox: this.getCoordinateBBox(), point: point,
line: line,
text: text,
autoAdjust: autoAdjust,
direction: direction });
}
else if (type === 'dataRegion') {
var _g = option, start = _g.start, end = _g.end, region = _g.region, text = _g.text, lineLength = _g.lineLength;
o = {
points: this.getRegionPoints(start, end),
region: region,
text: text,
lineLength: lineLength,
};
}
else if (type === 'regionFilter') {
var _h = option, start = _h.start, end = _h.end, apply_1 = _h.apply, color = _h.color;
var geometries = this.view.geometries;
var shapes_1 = [];
var addShapes_1 = function (item) {
if (!item) {
return;
}
if (item.isGroup()) {
item.getChildren().forEach(function (child) { return addShapes_1(child); });
}
else {
shapes_1.push(item);
}
};
each(geometries, function (geom) {
if (apply_1) {
if (contains(apply_1, geom.type)) {
each(geom.elements, function (elem) {
addShapes_1(elem.shape);
});
}
}
else {
each(geom.elements, function (elem) {
addShapes_1(elem.shape);
});
}
});
o = {
color: color,
shapes: shapes_1,
start: this.parsePosition(start),
end: this.parsePosition(end),
};
}
// 合并主题,用户配置优先级高于默认主题
var cfg = deepMix({}, theme, __assign(__assign({}, o), { top: option.top, style: option.style, offsetX: option.offsetX, offsetY: option.offsetY }));
cfg.container = this.getComponentContainer(cfg);
cfg.animate = this.view.getOptions().animate && cfg.animate && get(option, 'animate', cfg.animate); // 如果 view 关闭动画,则不执行
cfg.animateOption = deepMix({}, DEFAULT_ANIMATE_CFG, cfg.animateOption, option.animateOption);
return cfg;
};
/**
* is annotation render on top
* @param option
* @return whethe on top
*/
Annotation.prototype.isTop = function (option) {
return get(option, 'top', true);
};
/**
* get the container by option.top
* default is on top
* @param option
* @returns the container
*/
Annotation.prototype.getComponentContainer = function (option) {
return this.isTop(option) ? this.foregroundContainer : this.backgroundContainer;
};
Annotation.prototype.getAnnotationTheme = function (type) {
return get(this.view.getTheme(), ['components', 'annotation', type], {});
};
return Annotation;
}(Controller));
export default Annotation;
//# sourceMappingURL=annotation.js.map