@antv/g2
Version:
the Grammar of Graphics in Javascript
100 lines (92 loc) • 3.19 kB
text/typescript
import { each, pick } from '@antv/util';
import { BBox, IGroup, IShape } from '../../../dependents';
import { getCoordinateBBox } from '../../../util/coordinate';
import { getEllipsisText } from '../../../util/text';
import { translate } from '../../../util/transform';
import { LabelItem } from '../interface';
/** limitInPlot layout 的可选配置 */
export interface LimitInPlotLayoutCfg {
/** 需要限制哪些方向上不能超过 Plot 范围,默认四个方向上都限制 */
direction?: ('top' | 'right' | 'bottom' | 'left')[];
/** 可以允许的 margin */
margin?: number;
/** 超过限制后的动作,默认 translate 移动位置; ellipsis 对 text 进行省略展示 */
action?: 'hide' | 'translate' | 'ellipsis';
}
/**
* @ignore
* 将 label 限制在 Plot 范围内,将超出 Plot 范围的 label 可选择进行隐藏或者移动位置
* @param labels
* @param cfg
*/
export function limitInPlot(
items: LabelItem[],
labels: IGroup[],
shapes: IShape[] | IGroup[],
region: BBox,
cfg?: LimitInPlotLayoutCfg
) {
if (labels.length <= 0) {
return;
}
const direction = cfg?.direction || ['top', 'right', 'bottom', 'left'];
const action = cfg?.action || 'translate';
const margin = cfg?.margin || 0;
const coordinate = labels[0].get('coordinate');
if (!coordinate) {
return;
}
const {
minX: regionMinX,
minY: regionMinY,
maxX: regionMaxX,
maxY: regionMaxY,
} = getCoordinateBBox(coordinate, margin);
each(labels, (label: IGroup) => {
const { minX, minY, maxX, maxY, x, y, width, height } = label.getCanvasBBox();
let finalX = x;
let finalY = y;
if (direction.indexOf('left') >= 0 && (minX < regionMinX || maxX < regionMinX)) {
// 超出左侧
finalX = regionMinX;
}
if (direction.indexOf('top') >= 0 && (minY < regionMinY || maxY < regionMinY)) {
// 超出顶部
finalY = regionMinY;
}
if (direction.indexOf('right') >= 0) {
if (minX > regionMaxX) {
// 整体超出右侧
finalX = regionMaxX - width;
} else if (maxX > regionMaxX) {
// 超出右侧
finalX = finalX - (maxX - regionMaxX);
}
}
if (direction.indexOf('bottom') >= 0) {
if (minY > regionMaxY) {
// 整体超出底部
finalY = regionMaxY - height;
} else if (maxY > regionMaxY) {
// 超出底部
finalY = finalY - (maxY - regionMaxY);
}
}
if (finalX !== x || finalY !== y) {
const translateX = finalX - x;
if (action === 'translate') {
translate(label, translateX, finalY - y);
} else if (action === 'ellipsis') {
const textShapes = label.findAll((shape) => shape.get('type') === 'text');
textShapes.forEach((textShape) => {
const style = pick(textShape.attr(), ['fontSize', 'fontFamily', 'fontWeight', 'fontStyle', 'fontVariant']);
const textBox = textShape.getCanvasBBox();
const text = getEllipsisText(textShape.attr('text'), textBox.width - Math.abs(translateX), style);
textShape.attr('text', text);
});
} else {
label.hide();
}
}
});
}