@antv/g2
Version:
the Grammar of Graphics in Javascript
262 lines (238 loc) • 6.22 kB
text/typescript
import { deepMix, get, isBoolean } from '@antv/util';
import { DIRECTION } from '../constant';
import { Coordinate, Scale } from '../dependents';
import { AxisCfg, AxisOption, Point, Region } from '../interface';
import { getName } from './scale';
import { vec2 } from '@antv/matrix-util';
/**
* @ignore
* get axis relative region ( 0 ~ 1) by direction when coordinate is rect
* @param direction
* @returns axis coordinate region
*/
export function getLineAxisRelativeRegion(direction: DIRECTION): Region {
let start;
let end;
switch (direction) {
case DIRECTION.TOP:
start = { x: 0, y: 1 };
end = { x: 1, y: 1 };
break;
case DIRECTION.RIGHT:
start = { x: 1, y: 0 };
end = { x: 1, y: 1 };
break;
case DIRECTION.BOTTOM:
start = { x: 0, y: 0 };
end = { x: 1, y: 0 };
break;
case DIRECTION.LEFT:
start = { x: 0, y: 0 };
end = { x: 0, y: 1 };
break;
default:
start = end = { x: 0, y: 0 };
}
return { start, end };
}
/**
* @ignore
* get axis relative region ( 0 ~ 1) by direction when coordinate is polar
* @param coordinate
* @returns axis coordinate region
*/
export function getCircleAxisRelativeRegion(coordinate: Coordinate) {
let start;
let end;
if (coordinate.isTransposed) {
start = {
x: 0,
y: 0,
};
end = {
x: 1,
y: 0,
};
} else {
start = {
x: 0,
y: 0,
};
end = {
x: 0,
y: 1,
};
}
return { start, end };
}
/**
* @ignore
* get the axis region from coordinate
* @param coordinate
* @param direction
* @returns the axis region (start point, end point)
*/
export function getAxisRegion(coordinate: Coordinate, direction: DIRECTION): Region {
let region = { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } };
if (coordinate.isRect) {
region = getLineAxisRelativeRegion(direction);
} else if (coordinate.isPolar) {
region = getCircleAxisRelativeRegion(coordinate);
}
const { start, end } = region;
return {
start: coordinate.convert(start),
end: coordinate.convert(end),
};
}
/**
* @ignore
* get axis factor
* @param coordinate
* @param direction
* @returns factor
*/
export function getAxisFactor(coordinate: Coordinate, direction: DIRECTION): number {
// rect coordinate, by direction
if (coordinate.isRect) {
return coordinate.isTransposed
? [DIRECTION.RIGHT, DIRECTION.BOTTOM].includes(direction)
? 1
: -1
: [DIRECTION.BOTTOM, DIRECTION.RIGHT].includes(direction)
? -1
: 1;
}
// polar y axis, by angle
if (coordinate.isPolar) {
const startAngle = coordinate.x.start;
return startAngle < 0 ? -1 : 1;
}
return 1;
}
/**
* @ignore
* whether the axis isVertical
* @param region
* @returns isVertical
*/
export function isVertical(region: Region): boolean {
const { start, end } = region;
return start.x === end.x;
}
/**
* @ignore
* get factor by region (real position)
* @param region
* @param center
* @returns factor
*/
export function getAxisFactorByRegion(region: Region, center: Point): number {
const { start, end } = region;
const isAxisVertical = isVertical(region);
// 垂直
if (isAxisVertical) {
// 左方,从下到上、右方,从上到下
if ((start.y - end.y) * (center.x - start.x) > 0) {
return 1;
} else {
return -1;
}
} else {
// 下方,从左到右、上方,从右到做
if ((end.x - start.x) * (start.y - center.y) > 0) {
return -1;
} else {
return 1;
}
}
}
/**
* @ignore
* get the axis cfg from theme, will mix the common cfg of legend theme
*
* @param theme view theme object
* @param direction axis direction
* @returns axis theme cfg
*/
export function getAxisThemeCfg(theme: object, direction: string): object {
const axisTheme = get(theme, ['components', 'axis'], {});
return deepMix({}, get(axisTheme, ['common'], {}), deepMix({}, get(axisTheme, [direction], {})));
}
/**
* get the options of axis title,mix the cfg from theme, avoid common themeCfg not work
* @param theme
* @param direction
* @param axisOptions
* @returns axis title options
*/
export function getAxisTitleOptions(theme: object, direction: string, axisOptions?: object): object {
const axisTheme = get(theme, ['components', 'axis'], {});
return deepMix(
{},
get(axisTheme, ['common', 'title'], {}),
deepMix({}, get(axisTheme, [direction, 'title'], {})),
axisOptions
);
}
/**
* @ignore
* get circle axis center and radius
* @param coordinate
*/
export function getCircleAxisCenterRadius(coordinate: Coordinate) {
// @ts-ignore
const { x, y, circleCenter: center } = coordinate;
const isReflectY = y.start > y.end;
const start = coordinate.isTransposed
? coordinate.convert({
x: isReflectY ? 0 : 1,
y: 0,
})
: coordinate.convert({
x: 0,
y: isReflectY ? 0 : 1,
});
const startVector: [number, number] = [start.x - center.x, start.y - center.y];
const normalVector: [number, number] = [1, 0];
const startAngle =
start.y > center.y ? vec2.angle(startVector, normalVector) : vec2.angle(startVector, normalVector) * -1;
const endAngle = startAngle + (x.end - x.start);
const radius = Math.sqrt((start.x - center.x) ** 2 + (start.y - center.y) ** 2);
return {
center,
radius,
startAngle,
endAngle,
};
}
/**
* @ignore
* 从配置中获取单个字段的 axis 配置
* @param axes
* @param field
* @returns the axis option of field
*/
export function getAxisOption(axes: Record<string, AxisOption> | boolean, field: string) {
if (isBoolean(axes)) {
return axes === false ? false : {};
}
return get(axes, [field]);
}
/**
* @ignore
* 如果配置了 position,则使用配置
* @param axisOption
* @param def
*/
export function getAxisDirection(axisOption: AxisOption, def: DIRECTION): DIRECTION {
return get(axisOption, 'position', def);
}
/**
* 获取 axis 的 title 文本
* @param scale
* @param axisOption
*/
export function getAxisTitleText(scale: Scale, axisOption: AxisCfg): string {
return get(axisOption, ['title', 'text'], getName(scale));
}