@antv/g2
Version:
the Grammar of Graphics in Javascript
142 lines (125 loc) • 3.96 kB
text/typescript
import { each, isArray } from '@antv/util';
import { IGroup, ShapeAttrs } from '../../../dependents';
import { Point, Position, RangePoint, ShapeInfo, ShapeMarkerCfg } from '../../../interface';
import { registerShape, registerShapeFactory } from '../base';
import { getPathPoints } from '../util/get-path-points';
import { getStyle } from '../util/get-style';
import { getLinePath, getSplinePath } from '../util/path';
import { splitPoints } from '../util/split-points';
import { getLineMarker } from './util';
function getShapeAttrs(cfg: ShapeInfo, smooth?: boolean, constraint?: Position[]) {
const { isStack, connectNulls, isInCircle, showSinglePoint } = cfg;
const shapeAttrs = getStyle(cfg, true, false, 'lineWidth');
const points = getPathPoints(cfg.points, connectNulls, showSinglePoint); // 根据 connectNulls 值处理 points
let path = [];
for (let i = 0, len = points.length; i < len; i++) {
const eachLinePoints = points[i];
path = path.concat(getPath(eachLinePoints, isInCircle, isStack, smooth, constraint, shapeAttrs));
}
shapeAttrs.path = path;
return shapeAttrs;
}
// 单条 path
function getSinglePath(
points: Point[],
isInCircle: boolean,
smooth?: boolean,
constraint?: Position[],
style?: ShapeAttrs
) {
if (points.length === 1) {
// 只有一个点时
return [
['M', points[0].x, points[0].y - style.lineWidth / 2],
['L', points[0].x, points[0].y],
['L', points[0].x, points[0].y + style.lineWidth / 2],
];
}
let path;
if (!smooth) {
path = getLinePath(points, false);
if (isInCircle) {
path.push(['Z']);
}
} else {
// 直角坐标系下绘制曲线时限制最大值、最小值
if (isInCircle && points.length) {
points.push({ x: points[0].x, y: points[0].y });
}
path = getSplinePath(points, false, constraint);
}
return path;
}
function getRangePath(
points: RangePoint[],
isInCircle: boolean,
isStack?: boolean,
smooth?: boolean,
constraint?: Position[],
style?: ShapeAttrs
) {
const topPoints = [];
const bottomPoints = [];
each(points, (point: RangePoint) => {
const result = splitPoints(point);
topPoints.push(result[1]); // 上边
bottomPoints.push(result[0]); // 底边
});
const topPath = getSinglePath(topPoints, isInCircle, smooth, constraint, style);
const bottomPath = getSinglePath(bottomPoints, isInCircle, smooth, constraint, style);
if (isStack) {
return topPath;
}
return topPath.concat(bottomPath);
}
/**
* 获取折线图 path
*/
export function getPath(
points: Point[] | RangePoint[],
isInCircle: boolean,
isStack?: boolean,
smooth?: boolean,
constraint?: Position[],
style?: ShapeAttrs
) {
if (points.length) {
const first = points[0];
return isArray(first.y)
? getRangePath(points as RangePoint[], isInCircle, isStack, smooth, constraint, style)
: getSinglePath(points as Point[], isInCircle, smooth, constraint, style);
}
return [];
}
const LineShapeFactory = registerShapeFactory('line', {
defaultShapeType: 'line',
});
// 这里因为代码公用,所以直接全部注册
// 'line' 默认折线;'dot' 点线 ···;'dash' 断线 - - -
each(['line', 'dot', 'dash', 'smooth'], (shapeType) => {
registerShape('line', shapeType, {
draw(cfg: ShapeInfo, container: IGroup) {
const smooth = shapeType === 'smooth';
let constraint;
if (smooth) {
const { start, end } = this.coordinate;
constraint = [
[start.x, end.y],
[end.x, start.y],
];
}
const attrs = getShapeAttrs(cfg, smooth, constraint);
const shape = container.addShape({
type: 'path',
attrs,
name: 'line',
capture: !smooth,
});
return shape;
},
getMarker(markerCfg: ShapeMarkerCfg) {
return getLineMarker(markerCfg, shapeType);
},
});
});
export default LineShapeFactory;