@antv/g2
Version:
the Grammar of Graphics in Javascript
178 lines (151 loc) • 3.71 kB
text/typescript
import { each, isNil, some } from '@antv/util';
import { Coordinate, getCoordinate, Point } from '../../dependents';
import { CoordinateOption } from '../../interface';
/**
* coordinate controller,职责:
* 1. 创建实例
* 2. 暂存配置
*/
export default class CoordinateController {
private option: CoordinateOption;
private coordinate: Coordinate;
constructor(option?: CoordinateOption) {
// 设置默认值,并存储配置
this.option = this.wrapperOption(option);
}
/**
* 更新配置
* @param option
*/
public update(option: CoordinateOption) {
this.option = this.wrapperOption(option);
return this;
}
/**
* 是否存在某一个 action
* @param actionName
*/
public hasAction(actionName: string) {
const { actions } = this.option;
return some(actions, (action) => action[0] === actionName);
}
/**
* 创建坐标系对象
* @param start 起始位置
* @param end 结束位置
* @return 坐标系实例
*/
public create(start: Point, end: Point) {
const { type, cfg } = this.option;
const isTheta = type === 'theta';
// 1. 起始位置
const props = {
start,
end,
...cfg,
};
// 2. 创建实例
const C = getCoordinate(isTheta ? 'polar' : type);
this.coordinate = new C(props);
// @ts-ignore FIXME coordinate 包问题导致 type 不正确
this.coordinate.type = type;
// 3. 添加默认 action
if (isTheta) {
// 不存在 transpose,为其自动设置一个 action
if (!this.hasAction('transpose')) {
this.transpose();
}
}
// 4. 执行 action
this.execActions();
return this.coordinate;
}
/**
* 更新坐标系对象
* @param start 起始位置
* @param end 结束位置
* @return 坐标系实例
*/
public adjust(start: Point, end: Point) {
this.coordinate.update({
start,
end,
});
// 更新坐标系大小的时候,需要:
// 1. 重置 matrix
// 2. 重新执行作用于 matrix 的 action
this.coordinate.resetMatrix();
this.execActions(['scale', 'rotate', 'translate']);
return this.coordinate;
}
/**
* 旋转弧度
* @param angle
*/
public rotate(angle: number) {
this.option.actions.push(['rotate', angle]);
return this;
}
/**
* 镜像
* @param dim
*/
public reflect(dim: 'x' | 'y') {
this.option.actions.push(['reflect', dim]);
return this;
}
/**
* scale
* @param sx
* @param sy
*/
public scale(sx: number, sy: number) {
this.option.actions.push(['scale', sx, sy]);
return this;
}
/**
* 对角变换
*/
public transpose() {
this.option.actions.push(['transpose']);
return this;
}
/**
* 获取配置
*/
public getOption(): CoordinateOption {
return this.option;
}
/**
* 获得 coordinate 实例
*/
public getCoordinate() {
return this.coordinate;
}
/**
* 包装配置的默认值
* @param option
*/
private wrapperOption(option: CoordinateOption): CoordinateOption {
return {
type: 'rect',
actions: [],
cfg: {},
...option,
};
}
/**
* coordinate 实例执行 actions
* @params includeActions 如果没有指定,则执行全部,否则,执行指定的 action
*/
private execActions(includeActions?: string[]) {
const { actions } = this.option;
each(actions, (action) => {
const [actionName, ...args] = action;
const shouldExec = isNil(includeActions) ? true : includeActions.includes(actionName);
if (shouldExec) {
this.coordinate[actionName](...args);
}
});
}
}