import { Base } from '@antv/g-base'; import { deepMix, each, hasKey, isObject } from '@antv/util'; import { ILocation } from '../interfaces'; import { BBox, ComponentCfg, LocationCfg, OffsetPoint } from '../types'; const LOCATION_FIELD_MAP = { none: [], point: ['x', 'y'], region: ['start', 'end'], points: ['points'], circle: ['center', 'radius', 'startAngle', 'endAngle'], }; abstract class Component extends Base implements ILocation { constructor(cfg: T) { super(cfg); this.initCfg(); } /** * @protected * 默认的配置项 * @returns {object} 默认的配置项 */ public getDefaultCfg() { return { id: '', name: '', type: '', locationType: 'none', offsetX: 0, offsetY: 0, animate: false, capture: true, updateAutoRender: false, animateOption: { appear: null, // 初始入场动画配置 update: { duration: 400, easing: 'easeQuadInOut', }, // 更新时发生变更的动画配置 enter: { duration: 400, easing: 'easeQuadInOut', }, // 更新时新增元素的入场动画配置 leave: { duration: 350, easing: 'easeQuadIn', }, // 更新时销毁动画配置 }, events: null, defaultCfg: {}, visible: true, }; } /** * 清理组件的内容,一般配合 render 使用 * @example * axis.clear(); * axis.render(); */ public clear() {} /** * 更新组件 * @param {object} cfg 更新属性 */ public update(cfg: Partial) { const defaultCfg = this.get('defaultCfg'); each(cfg, (value, name) => { const originCfg = this.get(name); let newCfg = value; if (originCfg !== value) { // 判断两者是否相等,主要是进行 null 的判定 if (isObject(value) && defaultCfg[name]) { // 新设置的属性与默认值进行合并 newCfg = deepMix({}, defaultCfg[name], value); } this.set(name, newCfg); } }); this.updateInner(cfg); this.afterUpdate(cfg); } // 更新内部 protected updateInner(cfg: Partial) { } protected afterUpdate(cfg: Partial) { // 更新时考虑显示、隐藏 if (hasKey(cfg, 'visible')) { if (cfg.visible) { this.show(); } else { this.hide(); } } // 更新时考虑capture if (hasKey(cfg, 'capture')) { this.setCapture(cfg.capture); } } public abstract getBBox(): BBox; public getLayoutBBox(): BBox { return this.getBBox(); // 默认返回 getBBox,不同的组件内部单独实现 } public getLocationType() { return this.get('locationType'); } public getOffset(): OffsetPoint { return { offsetX: this.get('offsetX'), offsetY: this.get('offsetY'), }; } // 默认使用 update public setOffset(offsetX: number, offsetY: number) { this.update({ offsetX, offsetY, } as T); } public setLocation(cfg: LocationCfg) { const location = { ...cfg } as Partial; this.update(location); } // 实现 ILocation 接口的 getLocation public getLocation(): LocationCfg { const location = {} as LocationCfg; const locationType = this.get('locationType'); const fields = LOCATION_FIELD_MAP[locationType]; each(fields, (field) => { location[field] = this.get(field); }); return location; } public isList(): boolean { return false; } public isSlider(): boolean { return false; } /** * @protected * 初始化,用于具体的组件继承 */ public init() {} /** * 绘制组件 */ public abstract render(); /** * 显示 */ public abstract show(); public abstract setCapture(capture: boolean); /** * 隐藏 */ public abstract hide(); // 将组件默认的配置项设置合并到传入的配置项 private initCfg() { const defaultCfg = this.get('defaultCfg'); each(defaultCfg, (value, name) => { const cfg = this.get(name); if (isObject(cfg)) { const newCfg = deepMix({}, value, cfg); this.set(name, newCfg); } }); } } export default Component;