UNPKG

15 kBJavaScriptView Raw
1import { __assign, __awaiter, __generator, __rest, __values } from "tslib";
2import { deepMix, each, get, isArray, isNull } from '@antv/util';
3import { doAnimate } from '../animate';
4import { getGeometryLabelLayout } from '../geometry/label';
5import { getLabelBackgroundInfo } from '../geometry/label/util';
6import { polarToCartesian } from '../util/graphics';
7import { rotate, translate } from '../util/transform';
8import { FIELD_ORIGIN } from '../constant';
9import { updateLabel } from './update-label';
10/**
11 * Geometry labels 渲染组件
12 */
13var Labels = /** @class */ (function () {
14 function Labels(cfg) {
15 /** 存储当前 shape 的映射表,键值为 shape id */
16 this.shapesMap = {};
17 var layout = cfg.layout, container = cfg.container;
18 this.layout = layout;
19 this.container = container;
20 }
21 /**
22 * 渲染文本
23 */
24 Labels.prototype.render = function (items, shapes, isUpdate) {
25 if (isUpdate === void 0) { isUpdate = false; }
26 return __awaiter(this, void 0, void 0, function () {
27 var shapesMap, offscreenGroup, items_1, items_1_1, item, lastShapesMap;
28 var e_1, _a;
29 var _this = this;
30 return __generator(this, function (_b) {
31 switch (_b.label) {
32 case 0:
33 shapesMap = {};
34 offscreenGroup = this.createOffscreenGroup();
35 if (!items.length) return [3 /*break*/, 2];
36 try {
37 // 如果 items 空的话就不进行绘制调整操作
38 // step 1: 在虚拟 group 中创建 shapes
39 for (items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
40 item = items_1_1.value;
41 if (item) {
42 shapesMap[item.id] = this.renderLabel(item, offscreenGroup);
43 }
44 }
45 }
46 catch (e_1_1) { e_1 = { error: e_1_1 }; }
47 finally {
48 try {
49 if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
50 }
51 finally { if (e_1) throw e_1.error; }
52 }
53 // [todo] Move layout into Worker.
54 // step 2: 根据布局,调整 labels
55 return [4 /*yield*/, this.doLayout(items, shapes, shapesMap)];
56 case 1:
57 // [todo] Move layout into Worker.
58 // step 2: 根据布局,调整 labels
59 _b.sent();
60 // step 3.1: 绘制 labelLine
61 this.renderLabelLine(items, shapesMap);
62 // step 3.2: 绘制 labelBackground
63 this.renderLabelBackground(items, shapesMap);
64 // step 4: 根据用户设置的偏移量调整 label
65 this.adjustLabel(items, shapesMap);
66 _b.label = 2;
67 case 2:
68 lastShapesMap = this.shapesMap;
69 each(shapesMap, function (shape, id) {
70 if (shape.destroyed) {
71 // label 在布局调整环节被删除了(doLayout)
72 delete shapesMap[id];
73 }
74 else {
75 if (lastShapesMap[id]) {
76 // 图形发生更新
77 var data = shape.get('data');
78 var origin_1 = shape.get('origin');
79 var coordinate = shape.get('coordinate');
80 var currentAnimateCfg = shape.get('animateCfg');
81 var currentShape = lastShapesMap[id]; // 已经在渲染树上的 shape
82 updateLabel(currentShape, shapesMap[id], {
83 data: data,
84 origin: origin_1,
85 animateCfg: currentAnimateCfg,
86 coordinate: coordinate,
87 });
88 shapesMap[id] = currentShape; // 保存引用
89 }
90 else {
91 // 新生成的 shape
92 // If container has been destroyed, no need to render labels.
93 if (_this.container.destroyed)
94 return;
95 _this.container.add(shape);
96 var animateCfg = get(shape.get('animateCfg'), isUpdate ? 'enter' : 'appear');
97 if (animateCfg) {
98 doAnimate(shape, animateCfg, {
99 toAttrs: __assign({}, shape.attr()),
100 coordinate: shape.get('coordinate'),
101 });
102 }
103 }
104 delete lastShapesMap[id];
105 }
106 });
107 // 移除
108 each(lastShapesMap, function (deleteShape) {
109 var animateCfg = get(deleteShape.get('animateCfg'), 'leave');
110 if (animateCfg) {
111 doAnimate(deleteShape, animateCfg, {
112 toAttrs: null,
113 coordinate: deleteShape.get('coordinate'),
114 });
115 }
116 else {
117 deleteShape.remove(true); // 移除
118 }
119 });
120 this.shapesMap = shapesMap;
121 offscreenGroup.destroy();
122 return [2 /*return*/];
123 }
124 });
125 });
126 };
127 /** 清除当前 labels */
128 Labels.prototype.clear = function () {
129 this.container.clear();
130 this.shapesMap = {};
131 };
132 /** 销毁 */
133 Labels.prototype.destroy = function () {
134 this.container.destroy();
135 this.shapesMap = null;
136 };
137 Labels.prototype.renderLabel = function (cfg, container) {
138 var id = cfg.id, elementId = cfg.elementId, data = cfg.data, mappingData = cfg.mappingData, coordinate = cfg.coordinate, animate = cfg.animate, content = cfg.content;
139 var shapeAppendCfg = {
140 id: id,
141 elementId: elementId,
142 data: data,
143 origin: __assign(__assign({}, mappingData), { data: mappingData[FIELD_ORIGIN] }),
144 coordinate: coordinate,
145 };
146 var labelGroup = container.addGroup(__assign({ name: 'label',
147 // 如果 this.animate === false 或者 cfg.animate === false/null 则不进行动画,否则进行动画配置的合并
148 animateCfg: this.animate === false || animate === null || animate === false ? false : deepMix({}, this.animate, animate) }, shapeAppendCfg));
149 var labelShape;
150 if ((content.isGroup && content.isGroup()) || (content.isShape && content.isShape())) {
151 // 如果 content 是 Group 或者 Shape,根据 textAlign 调整位置后,直接将其加入 labelGroup
152 var _a = content.getCanvasBBox(), width = _a.width, height = _a.height;
153 var textAlign = get(cfg, 'textAlign', 'left');
154 var x = cfg.x;
155 var y = cfg.y - height / 2;
156 if (textAlign === 'center') {
157 x = x - width / 2;
158 }
159 else if (textAlign === 'right' || textAlign === 'end') {
160 x = x - width;
161 }
162 translate(content, x, y); // 将 label 平移至 x, y 指定的位置
163 labelShape = content;
164 labelGroup.add(content);
165 }
166 else {
167 var fill = get(cfg, ['style', 'fill']);
168 labelShape = labelGroup.addShape('text', __assign({ attrs: __assign(__assign({ x: cfg.x, y: cfg.y, textAlign: cfg.textAlign, textBaseline: get(cfg, 'textBaseline', 'middle'), text: cfg.content }, cfg.style), { fill: isNull(fill) ? cfg.color : fill }) }, shapeAppendCfg));
169 }
170 if (cfg.rotate) {
171 rotate(labelShape, cfg.rotate);
172 }
173 return labelGroup;
174 };
175 // 根据type对label布局
176 Labels.prototype.doLayout = function (items, shapes, shapesMap) {
177 return __awaiter(this, void 0, void 0, function () {
178 var layouts;
179 var _this = this;
180 return __generator(this, function (_a) {
181 switch (_a.label) {
182 case 0:
183 if (!this.layout) return [3 /*break*/, 2];
184 layouts = isArray(this.layout) ? this.layout : [this.layout];
185 return [4 /*yield*/, Promise.all(layouts.map(function (layout) {
186 var layoutFn = getGeometryLabelLayout(get(layout, 'type', ''));
187 if (!layoutFn)
188 return;
189 var labelShapes = [];
190 var geometryShapes = [];
191 each(shapesMap, function (labelShape, id) {
192 labelShapes.push(labelShape);
193 geometryShapes.push(shapes[labelShape.get('elementId')]);
194 });
195 // [todo] Refactor more layout into Worker.
196 return layoutFn(items, labelShapes, geometryShapes, _this.region, layout.cfg);
197 }))];
198 case 1:
199 _a.sent();
200 _a.label = 2;
201 case 2: return [2 /*return*/];
202 }
203 });
204 });
205 };
206 Labels.prototype.renderLabelLine = function (labelItems, shapesMap) {
207 each(labelItems, function (labelItem) {
208 var coordinate = get(labelItem, 'coordinate');
209 if (!labelItem || !coordinate) {
210 return;
211 }
212 var center = coordinate.getCenter();
213 var radius = coordinate.getRadius();
214 if (!labelItem.labelLine) {
215 // labelLine: null | false,关闭 label 对应的 labelLine
216 return;
217 }
218 var labelLineCfg = get(labelItem, 'labelLine', {});
219 var id = labelItem.id;
220 var path = labelLineCfg.path;
221 if (!path) {
222 var start = polarToCartesian(center.x, center.y, radius, labelItem.angle);
223 path = [
224 ['M', start.x, start.y],
225 ['L', labelItem.x, labelItem.y],
226 ];
227 }
228 var labelGroup = shapesMap[id];
229 if (!labelGroup.destroyed) {
230 labelGroup.addShape('path', {
231 capture: false,
232 attrs: __assign({ path: path, stroke: labelItem.color ? labelItem.color : get(labelItem, ['style', 'fill'], '#000'), fill: null }, labelLineCfg.style),
233 id: id,
234 origin: labelItem.mappingData,
235 data: labelItem.data,
236 coordinate: labelItem.coordinate,
237 });
238 }
239 });
240 };
241 /**
242 * 绘制标签背景
243 * @param labelItems
244 */
245 Labels.prototype.renderLabelBackground = function (labelItems, shapesMap) {
246 each(labelItems, function (labelItem) {
247 var coordinate = get(labelItem, 'coordinate');
248 var background = get(labelItem, 'background');
249 if (!background || !coordinate) {
250 return;
251 }
252 var id = labelItem.id;
253 var labelGroup = shapesMap[id];
254 if (!labelGroup.destroyed) {
255 var labelContentShape = labelGroup.getChildren()[0];
256 if (labelContentShape) {
257 var _a = getLabelBackgroundInfo(labelGroup, labelItem, background.padding), rotation = _a.rotation, box = __rest(_a, ["rotation"]);
258 var backgroundShape = labelGroup.addShape('rect', {
259 attrs: __assign(__assign({}, box), (background.style || {})),
260 id: id,
261 origin: labelItem.mappingData,
262 data: labelItem.data,
263 coordinate: labelItem.coordinate,
264 });
265 backgroundShape.setZIndex(-1);
266 if (rotation) {
267 var matrix = labelContentShape.getMatrix();
268 backgroundShape.setMatrix(matrix);
269 }
270 }
271 }
272 });
273 };
274 Labels.prototype.createOffscreenGroup = function () {
275 var container = this.container;
276 var GroupClass = container.getGroupBase(); // 获取分组的构造函数
277 var newGroup = new GroupClass({});
278 return newGroup;
279 };
280 Labels.prototype.adjustLabel = function (items, shapesMap) {
281 each(items, function (item) {
282 if (item) {
283 var id = item.id;
284 var labelGroup = shapesMap[id];
285 if (!labelGroup.destroyed) {
286 // fix: 如果说开发者的 label content 是一个 group,此处的偏移无法对 整个 content group 生效;场景类似 饼图 spider label 是一个含 2 个 textShape 的 gorup
287 var labelShapes = labelGroup.findAll(function (ele) { return ele.get('type') !== 'path'; });
288 each(labelShapes, function (labelShape) {
289 if (labelShape) {
290 if (item.offsetX) {
291 labelShape.attr('x', labelShape.attr('x') + item.offsetX);
292 }
293 if (item.offsetY) {
294 labelShape.attr('y', labelShape.attr('y') + item.offsetY);
295 }
296 }
297 });
298 }
299 }
300 });
301 };
302 return Labels;
303}());
304export default Labels;
305//# sourceMappingURL=labels.js.map
\No newline at end of file