UNPKG

17.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var tslib_1 = require("tslib");
4var util_1 = require("@antv/util");
5// 暂未发包
6// @ts-ignore
7var component_1 = require("@antv/component");
8var animate_1 = require("../../animate");
9var base_1 = tslib_1.__importDefault(require("../../base"));
10var graphics_1 = require("../../util/graphics");
11var constant_1 = require("../../constant");
12var constant_2 = require("../shape/constant");
13/**
14 * Element 图形元素。
15 * 定义:在 G2 中,我们会将数据通过图形语法映射成不同的图形,比如点图,数据集中的每条数据会对应一个点,柱状图每条数据对应一个柱子,线图则是一组数据对应一条折线,Element 即一条/一组数据对应的图形元素,它代表一条数据或者一个数据集,在图形层面,它可以是单个 Shape 也可以是多个 Shape,我们称之为图形元素。
16 */
17var Element = /** @class */ (function (_super) {
18 tslib_1.__extends(Element, _super);
19 function Element(cfg) {
20 var _this = _super.call(this, cfg) || this;
21 /** 保存 shape 对应的 label */
22 _this.labelShape = [];
23 // 存储当前开启的状态
24 _this.states = [];
25 var shapeFactory = cfg.shapeFactory, container = cfg.container, offscreenGroup = cfg.offscreenGroup, elementIndex = cfg.elementIndex, _a = cfg.visible, visible = _a === void 0 ? true : _a;
26 _this.shapeFactory = shapeFactory;
27 _this.container = container;
28 _this.offscreenGroup = offscreenGroup;
29 _this.visible = visible;
30 _this.elementIndex = elementIndex;
31 return _this;
32 }
33 /**
34 * 绘制图形。
35 * @param model 绘制数据。
36 * @param isUpdate 可选,是否是更新发生后的绘制。
37 */
38 Element.prototype.draw = function (model, isUpdate) {
39 if (isUpdate === void 0) { isUpdate = false; }
40 this.model = model;
41 this.data = model.data; // 存储原始数据
42 this.shapeType = this.getShapeType(model);
43 // 绘制图形
44 this.drawShape(model, isUpdate);
45 if (this.visible === false) {
46 // 用户在初始化的时候声明 visible: false
47 this.changeVisible(false);
48 }
49 };
50 /**
51 * 更新图形。
52 * @param model 更新的绘制数据。
53 */
54 Element.prototype.update = function (model) {
55 var _a = this, shapeFactory = _a.shapeFactory, shape = _a.shape;
56 if (!shape) {
57 return;
58 }
59 // 更新数据
60 this.model = model;
61 this.data = model.data;
62 this.shapeType = this.getShapeType(model);
63 // step 1: 更新 shape 携带的信息
64 this.setShapeInfo(shape, model);
65 // step 2: 使用虚拟 Group 重新绘制 shape,然后更新当前 shape
66 var offscreenGroup = this.getOffscreenGroup();
67 var newShape = shapeFactory.drawShape(this.shapeType, model, offscreenGroup);
68 // @ts-ignore
69 newShape.cfg.data = this.data;
70 // @ts-ignore
71 newShape.cfg.origin = model;
72 // label 需要使用
73 newShape.cfg.element = this;
74 // step 3: 同步 shape 样式
75 this.syncShapeStyle(shape, newShape, this.getStates(), this.getAnimateCfg('update'));
76 };
77 /**
78 * 销毁 element 实例。
79 */
80 Element.prototype.destroy = function () {
81 var _a = this, shapeFactory = _a.shapeFactory, shape = _a.shape;
82 if (shape) {
83 var animateCfg = this.getAnimateCfg('leave');
84 if (animateCfg) {
85 // 指定了动画配置则执行销毁动画
86 (0, animate_1.doAnimate)(shape, animateCfg, {
87 coordinate: shapeFactory.coordinate,
88 toAttrs: tslib_1.__assign({}, shape.attr()),
89 });
90 }
91 else {
92 // 否则直接销毁
93 shape.remove(true);
94 }
95 }
96 // reset
97 this.states = [];
98 this.shapeFactory = undefined;
99 this.container = undefined;
100 this.shape = undefined;
101 this.animate = undefined;
102 this.geometry = undefined;
103 this.labelShape = [];
104 this.model = undefined;
105 this.data = undefined;
106 this.offscreenGroup = undefined;
107 this.statesStyle = undefined;
108 _super.prototype.destroy.call(this);
109 };
110 /**
111 * 显示或者隐藏 element。
112 * @param visible 是否可见。
113 */
114 Element.prototype.changeVisible = function (visible) {
115 _super.prototype.changeVisible.call(this, visible);
116 if (visible) {
117 if (this.shape) {
118 this.shape.show();
119 }
120 if (this.labelShape) {
121 this.labelShape.forEach(function (label) {
122 label.show();
123 });
124 }
125 }
126 else {
127 if (this.shape) {
128 this.shape.hide();
129 }
130 if (this.labelShape) {
131 this.labelShape.forEach(function (label) {
132 label.hide();
133 });
134 }
135 }
136 };
137 /**
138 * 设置 Element 的状态。
139 *
140 * 目前 Element 开放三种状态:
141 * 1. active
142 * 2. selected
143 * 3. inactive
144 *
145 * 这三种状态相互独立,可以进行叠加。
146 *
147 * 这三种状态的样式可在 [[Theme]] 主题中或者通过 `geometry.state()` 接口进行配置。
148 *
149 * ```ts
150 * // 激活 active 状态
151 * setState('active', true);
152 * ```
153 *
154 * @param stateName 状态名
155 * @param stateStatus 是否开启状态
156 */
157 Element.prototype.setState = function (stateName, stateStatus) {
158 var _a = this, states = _a.states, shapeFactory = _a.shapeFactory, model = _a.model, shape = _a.shape, shapeType = _a.shapeType;
159 var index = states.indexOf(stateName);
160 if (stateStatus) {
161 // 开启状态
162 if (index > -1) {
163 // 该状态已经开启,则返回
164 return;
165 }
166 states.push(stateName);
167 if (stateName === 'active' || stateName === 'selected') {
168 shape === null || shape === void 0 ? void 0 : shape.toFront();
169 }
170 }
171 else {
172 if (index === -1) {
173 // 关闭状态,但是状态未设置过
174 return;
175 }
176 states.splice(index, 1);
177 if (stateName === 'active' || stateName === 'selected') {
178 var _b = this.geometry, sortZIndex = _b.sortZIndex, zIndexReversed = _b.zIndexReversed;
179 var idx = zIndexReversed ? this.geometry.elements.length - this.elementIndex : this.elementIndex;
180 sortZIndex ? shape.setZIndex(idx) : shape.set('zIndex', idx);
181 }
182 }
183 // 使用虚拟 group 重新绘制 shape,然后对这个 shape 应用状态样式后,更新当前 shape。
184 var offscreenShape = shapeFactory.drawShape(shapeType, model, this.getOffscreenGroup());
185 if (states.length) {
186 // 应用当前状态
187 this.syncShapeStyle(shape, offscreenShape, states, null);
188 }
189 else {
190 // 如果没有状态,则需要恢复至原始状态
191 this.syncShapeStyle(shape, offscreenShape, ['reset'], null);
192 }
193 offscreenShape.remove(true); // 销毁,减少内存占用
194 var eventObject = {
195 state: stateName,
196 stateStatus: stateStatus,
197 element: this,
198 target: this.container,
199 };
200 this.container.emit('statechange', eventObject);
201 // @ts-ignore
202 (0, component_1.propagationDelegate)(this.shape, 'statechange', eventObject);
203 };
204 /**
205 * 清空状量态,恢复至初始状态。
206 */
207 Element.prototype.clearStates = function () {
208 var _this = this;
209 var states = this.states;
210 (0, util_1.each)(states, function (state) {
211 _this.setState(state, false);
212 });
213 this.states = [];
214 };
215 /**
216 * 查询当前 Element 上是否已设置 `stateName` 对应的状态。
217 * @param stateName 状态名称。
218 * @returns true 表示存在,false 表示不存在。
219 */
220 Element.prototype.hasState = function (stateName) {
221 return this.states.includes(stateName);
222 };
223 /**
224 * 获取当前 Element 上所有的状态。
225 * @returns 当前 Element 上所有的状态数组。
226 */
227 Element.prototype.getStates = function () {
228 return this.states;
229 };
230 /**
231 * 获取 Element 对应的原始数据。
232 * @returns 原始数据。
233 */
234 Element.prototype.getData = function () {
235 return this.data;
236 };
237 /**
238 * 获取 Element 对应的图形绘制数据。
239 * @returns 图形绘制数据。
240 */
241 Element.prototype.getModel = function () {
242 return this.model;
243 };
244 /**
245 * 返回 Element 元素整体的 bbox,包含文本及文本连线(有的话)。
246 * @returns 整体包围盒。
247 */
248 Element.prototype.getBBox = function () {
249 var _a = this, shape = _a.shape, labelShape = _a.labelShape;
250 var bbox = {
251 x: 0,
252 y: 0,
253 minX: 0,
254 minY: 0,
255 maxX: 0,
256 maxY: 0,
257 width: 0,
258 height: 0,
259 };
260 if (shape) {
261 bbox = shape.getCanvasBBox();
262 }
263 if (labelShape) {
264 labelShape.forEach(function (label) {
265 var labelBBox = label.getCanvasBBox();
266 bbox.x = Math.min(labelBBox.x, bbox.x);
267 bbox.y = Math.min(labelBBox.y, bbox.y);
268 bbox.minX = Math.min(labelBBox.minX, bbox.minX);
269 bbox.minY = Math.min(labelBBox.minY, bbox.minY);
270 bbox.maxX = Math.max(labelBBox.maxX, bbox.maxX);
271 bbox.maxY = Math.max(labelBBox.maxY, bbox.maxY);
272 });
273 }
274 bbox.width = bbox.maxX - bbox.minX;
275 bbox.height = bbox.maxY - bbox.minY;
276 return bbox;
277 };
278 Element.prototype.getStatesStyle = function () {
279 if (!this.statesStyle) {
280 var _a = this, shapeType = _a.shapeType, geometry = _a.geometry, shapeFactory = _a.shapeFactory;
281 var stateOption = geometry.stateOption;
282 var defaultShapeType = shapeFactory.defaultShapeType;
283 var stateTheme = shapeFactory.theme[shapeType] || shapeFactory.theme[defaultShapeType];
284 this.statesStyle = (0, util_1.deepMix)({}, stateTheme, stateOption);
285 }
286 return this.statesStyle;
287 };
288 // 从主题中获取对应状态量的样式
289 Element.prototype.getStateStyle = function (stateName, shapeKey) {
290 var statesStyle = this.getStatesStyle();
291 var stateCfg = (0, util_1.get)(statesStyle, [stateName, 'style'], {});
292 var shapeStyle = stateCfg[shapeKey] || stateCfg;
293 if ((0, util_1.isFunction)(shapeStyle)) {
294 return shapeStyle(this);
295 }
296 return shapeStyle;
297 };
298 // 获取动画配置
299 Element.prototype.getAnimateCfg = function (animateType) {
300 var _this = this;
301 var animate = this.animate;
302 if (animate) {
303 var cfg_1 = animate[animateType];
304 if (cfg_1) {
305 // 增加动画的回调函数,如果外部传入了,则先执行外部,然后发射 geometry 的 animate 事件
306 return tslib_1.__assign(tslib_1.__assign({}, cfg_1), { callback: function () {
307 var _a;
308 (0, util_1.isFunction)(cfg_1.callback) && cfg_1.callback();
309 (_a = _this.geometry) === null || _a === void 0 ? void 0 : _a.emit(constant_1.GEOMETRY_LIFE_CIRCLE.AFTER_DRAW_ANIMATE);
310 } });
311 }
312 return cfg_1;
313 }
314 return null;
315 };
316 // 绘制图形
317 Element.prototype.drawShape = function (model, isUpdate) {
318 var _a;
319 if (isUpdate === void 0) { isUpdate = false; }
320 var _b = this, shapeFactory = _b.shapeFactory, container = _b.container, shapeType = _b.shapeType;
321 // 自定义 shape 有可能返回空 shape
322 this.shape = shapeFactory.drawShape(shapeType, model, container);
323 if (this.shape) {
324 this.setShapeInfo(this.shape, model); // 存储绘图数据
325 // @ts-ignore
326 var name_1 = this.shape.cfg.name;
327 // 附加 element 的 name, name 现在支持数组了,很好用了
328 if (!name_1) {
329 // 这个地方如果用户添加了 name, 则附加 name ,否则就添加自己的 name
330 // @ts-ignore
331 this.shape.cfg.name = ['element', this.shapeFactory.geometryType];
332 }
333 else if ((0, util_1.isString)(name_1)) {
334 // @ts-ignore
335 this.shape.cfg.name = ['element', name_1];
336 }
337 // 执行入场动画
338 var animateType = isUpdate ? 'enter' : 'appear';
339 var animateCfg = this.getAnimateCfg(animateType);
340 if (animateCfg) {
341 // 开始执行动画的生命周期
342 (_a = this.geometry) === null || _a === void 0 ? void 0 : _a.emit(constant_1.GEOMETRY_LIFE_CIRCLE.BEFORE_DRAW_ANIMATE);
343 (0, animate_1.doAnimate)(this.shape, animateCfg, {
344 coordinate: shapeFactory.coordinate,
345 toAttrs: tslib_1.__assign({}, this.shape.attr()),
346 });
347 }
348 }
349 };
350 // 获取虚拟 Group
351 Element.prototype.getOffscreenGroup = function () {
352 if (!this.offscreenGroup) {
353 var GroupCtor = this.container.getGroupBase(); // 获取分组的构造函数
354 this.offscreenGroup = new GroupCtor({});
355 }
356 return this.offscreenGroup;
357 };
358 // 设置 shape 上需要携带的信息
359 Element.prototype.setShapeInfo = function (shape, data) {
360 var _this = this;
361 // @ts-ignore
362 shape.cfg.origin = data;
363 // @ts-ignore
364 shape.cfg.element = this;
365 if (shape.isGroup()) {
366 var children = shape.get('children');
367 children.forEach(function (child) {
368 _this.setShapeInfo(child, data);
369 });
370 }
371 };
372 // 更新当前 shape 的样式
373 Element.prototype.syncShapeStyle = function (sourceShape, targetShape, states, animateCfg, index) {
374 var _this = this;
375 var _a;
376 if (states === void 0) { states = []; }
377 if (index === void 0) { index = 0; }
378 if (!sourceShape || !targetShape) {
379 return;
380 }
381 // 所有的 shape 都需要同步 clip
382 var clip = sourceShape.get('clipShape');
383 var newClip = targetShape.get('clipShape');
384 this.syncShapeStyle(clip, newClip, states, animateCfg);
385 if (sourceShape.isGroup()) {
386 var children = sourceShape.get('children');
387 var newChildren = targetShape.get('children');
388 for (var i = 0; i < children.length; i++) {
389 this.syncShapeStyle(children[i], newChildren[i], states, animateCfg, index + i);
390 }
391 }
392 else {
393 if (!(0, util_1.isEmpty)(states) && !(0, util_1.isEqual)(states, ['reset'])) {
394 var name_2 = sourceShape.get('name');
395 if ((0, util_1.isArray)(name_2)) {
396 // 会附加 element 的 name
397 name_2 = name_2[1];
398 }
399 (0, util_1.each)(states, function (state) {
400 // background shape 不进行状态样式设置
401 if (targetShape.get('name') !== constant_2.BACKGROUND_SHAPE) {
402 var style = _this.getStateStyle(state, name_2 || index); // 如果用户没有设置 name,则默认根据索引值
403 targetShape.attr(style);
404 }
405 });
406 }
407 var newAttrs = (0, graphics_1.getReplaceAttrs)(sourceShape, targetShape);
408 if (this.animate) {
409 if (animateCfg) {
410 (_a = this.geometry) === null || _a === void 0 ? void 0 : _a.emit(constant_1.GEOMETRY_LIFE_CIRCLE.BEFORE_DRAW_ANIMATE);
411 // 需要进行动画
412 (0, animate_1.doAnimate)(sourceShape, animateCfg, {
413 coordinate: this.shapeFactory.coordinate,
414 toAttrs: newAttrs,
415 shapeModel: this.model,
416 });
417 }
418 else if (!(0, util_1.isEmpty)(states)) {
419 sourceShape.stopAnimate();
420 sourceShape.animate(newAttrs, {
421 duration: 300,
422 });
423 }
424 else {
425 sourceShape.attr(newAttrs);
426 }
427 }
428 else {
429 sourceShape.attr(newAttrs);
430 }
431 }
432 };
433 Element.prototype.getShapeType = function (model) {
434 var shape = (0, util_1.get)(model, 'shape');
435 return (0, util_1.isArray)(shape) ? shape[0] : shape;
436 };
437 return Element;
438}(base_1.default));
439exports.default = Element;
440//# sourceMappingURL=index.js.map
\No newline at end of file