Skip to content

Commit

Permalink
refactor: 重构 GeometryLabel。将 labels 组件的生成渲染移入 GeomtryLabel 中
Browse files Browse the repository at this point in the history
  • Loading branch information
simaQ committed Mar 20, 2020
1 parent 219126e commit 4537b96
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 85 deletions.
97 changes: 40 additions & 57 deletions src/geometry/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { getShapeFactory } from './shape/base';
import { group } from './util/group-data';
import { isModelChange } from './util/is-model-change';
import { parseFields } from './util/parse-fields';
import GeometryLabel from './label/base';

/** @ignore */
interface AttributeInstanceCfg {
Expand Down Expand Up @@ -192,17 +193,17 @@ export default class Geometry extends Base {
protected lastElementsMap: Record<string, Element> = {};
/** 是否生成多个点来绘制图形。 */
protected generatePoints: boolean = false;
/** 虚拟 Group,用于图形更新 */
protected offscreenGroup: IGroup;
/** 存储发生图形属性映射前的数据 */
protected beforeMappingData: Data[] = null;
/** 存储每个 shape 的默认 size,用于 Interval、Schema 几何标记 */
protected defaultSize: number;

private adjusts: Record<string, Adjust> = {};
private lastAttributeOption;
private labelsRenderer: Labels;
private idFields: string[] = [];
private geometryLabel: GeometryLabel;
/** 虚拟 Group,用于图形更新 */
private offscreenGroup: IGroup;

/**
* 创建 Geometry 实例。
Expand Down Expand Up @@ -875,13 +876,13 @@ export default class Geometry extends Base {
* @override
*/
public clear() {
const { container, labelsRenderer } = this;
const { container, geometryLabel } = this;
if (container) {
container.clear();
}

if (labelsRenderer) {
labelsRenderer.clear();
if (geometryLabel) {
geometryLabel.clear();
}

// 属性恢复至出厂状态
Expand Down Expand Up @@ -910,9 +911,9 @@ export default class Geometry extends Base {
this.offscreenGroup = null;
}

if (this.labelsRenderer) {
this.labelsRenderer.destroy();
this.labelsRenderer = null;
if (this.geometryLabel) {
this.geometryLabel.destroy();
this.geometryLabel = null;
}
super.destroy();
}
Expand Down Expand Up @@ -1176,6 +1177,18 @@ export default class Geometry extends Base {
return this.elements.map((element: Element) => element.shape);
}

/**
* 获取虚拟 Group。
* @returns
*/
public getOffscreenGroup() {
if (!this.offscreenGroup) {
const GroupCtor = this.container.getGroupBase(); // 获取分组的构造函数
this.offscreenGroup = new GroupCtor({});
}
return this.offscreenGroup;
}

/**
* 调整度量范围。主要针对发生层叠以及一些特殊需求的 Geometry,比如 Interval 下的柱状图 Y 轴默认从 0 开始。
*/
Expand Down Expand Up @@ -1318,34 +1331,25 @@ export default class Geometry extends Base {
return elements;
}

/**
* 获取虚拟 Group。
* @returns
*/
protected getOffscreenGroup() {
if (!this.offscreenGroup) {
const GroupCtor = this.container.getGroupBase(); // 获取分组的构造函数
this.offscreenGroup = new GroupCtor({});
}
return this.offscreenGroup;
}

/**
* 获取渲染的 label 类型。
*/
protected getLabelType(): string {
const { labelOption, coordinate, type } = this;
const coordinateType = coordinate.type;
let labelType = get(labelOption, ['cfg', 'type']) || 'base';
if (labelType === 'base') {
let labelType = get(labelOption, ['cfg', 'type']);
if (!labelType) {
// 用户未定义,则进行默认的逻辑
if (coordinateType === 'polar') {
// 极坐标文本
// 极坐标下使用通用的极坐标文本
labelType = 'polar';
} else if (coordinateType === 'theta') {
// 饼图文本
// theta 坐标系下使用饼图文本
labelType = 'pie';
} else if (type === 'interval' || type === 'polygon') {
labelType = 'interval';
} else {
labelType = 'base';
}
}

Expand Down Expand Up @@ -1803,40 +1807,19 @@ export default class Geometry extends Base {
}

private renderLabels(mappingArray: MappingDatum[], isUpdate: boolean = false) {
const { labelOption, animateOption, coordinate } = this;
const labelType = this.getLabelType();

const GeometryLabelsCtor = getGeometryLabel(labelType);
const geometryLabels = new GeometryLabelsCtor(this);
const labelItems = geometryLabels.getLabelItems(mappingArray);

let labelsRenderer = this.labelsRenderer;
if (!labelsRenderer) {
labelsRenderer = new Labels({
container: this.labelsContainer,
layout: get(labelOption, ['cfg', 'layout']),
});
this.labelsRenderer = labelsRenderer;
let geometryLabel = this.geometryLabel;

if (!geometryLabel) {
// 初次创建
const labelType = this.getLabelType();
const GeometryLabelsCtor = getGeometryLabel(labelType);
geometryLabel = new GeometryLabelsCtor(this);
this.geometryLabel = geometryLabel;
}
labelsRenderer.region = this.canvasRegion;

const shapes = {};
each(this.elementsMap, (element: Element, id: string) => {
shapes[id] = element.shape;
});
// 因为有可能 shape 还在进行动画,导致 shape.getBBox() 获取到的值不是最终态,所以需要从 offscreenGroup 获取
each(this.offscreenGroup.getChildren(), (child) => {
const id = this.getElementId(child.get('origin').mappingData);
shapes[id] = child;
});

// 设置动画配置,如果 geometry 的动画关闭了,那么 label 的动画也会关闭
labelsRenderer.animate = animateOption ? getDefaultAnimateCfg('label', coordinate) : false;

// 渲染文本
labelsRenderer.render(labelItems, shapes, isUpdate);
geometryLabel.render(mappingArray, isUpdate);

const labelsMap = this.labelsRenderer.shapesMap;
// 将 label 同 element 进行关联
const labelsMap = geometryLabel.labelsRenderer.shapesMap;
each(this.elementsMap, (element: Element, id) => {
const labels = filterLabelsById(id, labelsMap); // element 实例同 label 进行绑定
element.labelShape = labels;
Expand Down
100 changes: 87 additions & 13 deletions src/geometry/label/base.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { deepMix, each, get, isArray, isFunction, isNil, isNumber, isUndefined } from '@antv/util';

import { FIELD_ORIGIN } from '../../constant';
import { Coordinate, Scale } from '../../dependents';
import { Datum, LabelOption, LooseObject, MappingDatum, Point } from '../../interface';
import { LabelCfg, LabelItem, LabelPointCfg, TextAlign } from './interface';

import { getDefaultAnimateCfg } from '../../animate';
import { getPolygonCentroid } from '../../util/graphics';

import Labels from '../../component/labels';
import Geometry from '../base';
import { LabelCfg, LabelItem, LabelPointCfg, TextAlign } from './interface';
import Element from '../element';

export type GeometryLabelConstructor = new (cfg: any) => GeometryLabel;

Expand All @@ -22,16 +28,42 @@ function avg(arr: number[]) {
export default class GeometryLabel {
/** geometry 实例 */
public readonly geometry: Geometry;
/** 坐标系实例 */
protected coordinate: Coordinate;
/** 默认的 label 配置 */
protected defaultLabelCfg: LooseObject;
public labelsRenderer: Labels;

constructor(geometry: Geometry) {
this.geometry = geometry;
}

public render(mapppingArray: MappingDatum[], isUpdate: boolean) {
let labelItems = this.getItems(mapppingArray);
labelItems = this.adjustItems(labelItems);

this.drawLines(labelItems);

const labelsRenderer = this.getLabelsRenderer();
const shapes = this.getGeometryShapes();
// 渲染文本
labelsRenderer.render(labelItems, shapes, isUpdate);
}

public clear() {
const labelsRenderer = this.labelsRenderer;
if (labelsRenderer) {
labelsRenderer.clear();
}
}

public destroy() {
const labelsRenderer = this.labelsRenderer;
if (labelsRenderer) {
labelsRenderer.destroy();
}
this.labelsRenderer = null;
}

this.coordinate = geometry.coordinate;
this.defaultLabelCfg = get(geometry.theme, 'labels', {}); // 默认样式
// geometry 更新之后,对应的 Coordinate 也会更新,为了获取到最新鲜的 Coordinate,故使用方法获取
public getCoordinate() {
return this.geometry.coordinate;
}

/**
Expand All @@ -46,6 +78,13 @@ export default class GeometryLabel {
return items;
}

/**
* 获取 label 的默认配置
*/
protected getDefaultLabelCfg() {
return get(this.geometry.theme, 'labels', {});
}

/**
* 设置 label 位置
* @param labelPointCfg
Expand Down Expand Up @@ -113,7 +152,7 @@ export default class GeometryLabel {
* @returns
*/
protected getDefaultOffset(offset: number) {
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
const vector = this.getOffsetVector(offset);
return coordinate.isTransposed ? vector[0] : vector[1];
}
Expand All @@ -127,7 +166,7 @@ export default class GeometryLabel {
*/
protected getLabelOffset(labelCfg: LabelCfg, index: number, total: number) {
const offset = this.getDefaultOffset(labelCfg.offset);
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
const transposed = coordinate.isTransposed;
const dim = transposed ? 'x' : 'y';
const factor = transposed ? 1 : -1; // y 方向上越大,像素的坐标越小,所以transposed时将系数变成
Expand All @@ -152,7 +191,7 @@ export default class GeometryLabel {
* @returns label point
*/
protected getLabelPoint(labelCfg: LabelCfg, mappingData: MappingDatum, index: number): LabelPointCfg {
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
const total = labelCfg.content.length;

function getDimValue(value, idx) {
Expand Down Expand Up @@ -239,7 +278,7 @@ export default class GeometryLabel {
*/
protected getLabelAlign(item: LabelItem, index: number, total: number): TextAlign {
let align: TextAlign = 'center';
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
if (coordinate.isTransposed) {
const offset = this.getDefaultOffset(item.offset);
if (offset < 0) {
Expand Down Expand Up @@ -283,6 +322,26 @@ export default class GeometryLabel {
return labelId;
}

// 获取 labels 组件
private getLabelsRenderer() {
const { labelsContainer, labelOption, canvasRegion, animateOption } = this.geometry;
const coordinate = this.geometry.coordinate;

let labelsRenderer = this.labelsRenderer;
if (!labelsRenderer) {
labelsRenderer = new Labels({
container: labelsContainer,
layout: get(labelOption, ['cfg', 'layout']),
});
this.labelsRenderer = labelsRenderer;
}
labelsRenderer.region = canvasRegion;
// 设置动画配置,如果 geometry 的动画关闭了,那么 label 的动画也会关闭
labelsRenderer.animate = animateOption ? getDefaultAnimateCfg('label', coordinate) : false;

return labelsRenderer;
}

private getItems(mapppingArray: MappingDatum[]): LabelItem[] {
const items = [];
const labelCfgs = this.getLabelCfgs(mapppingArray);
Expand Down Expand Up @@ -319,7 +378,7 @@ export default class GeometryLabel {

private getLabelCfgs(mapppingArray: MappingDatum[]): LabelCfg[] {
const geometry = this.geometry;
const defaultLabelCfg = this.defaultLabelCfg;
const defaultLabelCfg = this.getDefaultLabelCfg();
const { type, theme, labelOption, scales, coordinate } = geometry;
const { fields, callback, cfg } = labelOption as LabelOption;
const labelScales = fields.map((field: string) => {
Expand Down Expand Up @@ -397,8 +456,23 @@ export default class GeometryLabel {
}

private getOffsetVector(offset = 0) {
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
// 如果 x,y 翻转,则偏移 x,否则偏移 y
return coordinate.isTransposed ? coordinate.applyMatrix(offset, 0) : coordinate.applyMatrix(0, offset);
}

private getGeometryShapes() {
const geometry = this.geometry;
const shapes = {};
each(geometry.elementsMap, (element: Element, id: string) => {
shapes[id] = element.shape;
});
// 因为有可能 shape 还在进行动画,导致 shape.getBBox() 获取到的值不是最终态,所以需要从 offscreenGroup 获取
each(geometry.getOffscreenGroup().getChildren(), (child) => {
const id = geometry.getElementId(child.get('origin').mappingData);
shapes[id] = child;
});

return shapes;
}
}
3 changes: 2 additions & 1 deletion src/geometry/label/interval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { LabelPointCfg } from './interface';
* 柱状图 label
*/
export default class IntervalLabel extends GeometryLabel {

protected setLabelPosition(labelPointCfg: LabelPointCfg, mappingData: MappingDatum, index: number, position: string) {
const coordinate = this.coordinate;
const coordinate = this.getCoordinate();
const transposed = coordinate.isTransposed;
const shapePoints = mappingData.points as Point[];
const point0 = coordinate.convert(shapePoints[0]);
Expand Down
Loading

0 comments on commit 4537b96

Please sign in to comment.