@antv/g2
Version:
the Grammar of Graphics in Javascript
159 lines (148 loc) • 5.02 kB
text/typescript
import { each, head, isEqual, last } from '@antv/util';
import { IShape } from '../../dependents';
import Element from '../../geometry/element/';
import { LooseObject } from '../../interface';
import { getAngle, getSectorPath } from '../../util/graphics';
import Action from './base';
/**
* 背景框的 Action
* @ignore
*/
class ActiveRegion extends Action {
private items: any[];
private regionPath: IShape;
/**
* 显示
*/
public show() {
const view = this.context.view;
const ev = this.context.event;
const tooltipItems = view.getTooltipItems({
x: ev.x,
y: ev.y,
});
if (isEqual(tooltipItems, this.items)) {
// 如果拾取数据同上次相同,则不重复绘制
return;
}
this.items = tooltipItems;
if (tooltipItems.length) {
const xField = view.getXScale().field;
const xValue = tooltipItems[0].data[xField];
// 根据 x 对应的值查找 elements
let elements: Element[] = [];
const geometries = view.geometries;
each(geometries, (geometry) => {
if (geometry.type === 'interval' || geometry.type === 'schema') {
const result = geometry.getElementsBy((ele) => {
const eleData = ele.getData();
return eleData[xField] === xValue;
});
elements = elements.concat(result);
}
});
// 根据 bbox 计算背景框的面积区域
if (elements.length) {
const coordinate = view.getCoordinate();
let firstBBox = elements[0].shape.getCanvasBBox();
let lastBBox = elements[0].shape.getCanvasBBox();
const groupBBox: LooseObject = firstBBox;
each(elements, (ele: Element) => {
const bbox = ele.shape.getCanvasBBox();
if (coordinate.isTransposed) {
if (bbox.minY < firstBBox.minY) {
firstBBox = bbox;
}
if (bbox.maxY > lastBBox.maxY) {
lastBBox = bbox;
}
} else {
if (bbox.minX < firstBBox.minX) {
firstBBox = bbox;
}
if (bbox.maxX > lastBBox.maxX) {
lastBBox = bbox;
}
}
groupBBox.x = Math.min(bbox.minX, groupBBox.minX);
groupBBox.y = Math.min(bbox.minY, groupBBox.minY);
groupBBox.width = Math.max(bbox.maxX, groupBBox.maxX) - groupBBox.x;
groupBBox.height = Math.max(bbox.maxY, groupBBox.maxY) - groupBBox.y;
});
const { backgroundGroup, coordinateBBox } = view;
let path;
if (coordinate.isRect) {
const xScale = view.getXScale();
const appendRatio = xScale.isLinear ? 0 : 0.25; // 如果 x 轴是数值类型,如直方图,不需要家额外的宽度
let minX: number;
let minY: number;
let width: number;
let height: number;
if (coordinate.isTransposed) {
minX = coordinateBBox.minX;
minY = Math.min(lastBBox.minY, firstBBox.minY) - appendRatio * lastBBox.height;
width = coordinateBBox.width;
height = groupBBox.height + appendRatio * 2 * lastBBox.height;
} else {
minX = Math.min(firstBBox.minX, lastBBox.minX) - appendRatio * firstBBox.width;
minY = Math.min(coordinateBBox.minY, firstBBox.minY);
width = groupBBox.width + appendRatio * 2 * firstBBox.width;
height = coordinateBBox.height;
}
path = [
['M', minX, minY],
['L', minX + width, minY],
['L', minX + width, minY + height],
['L', minX, minY + height],
['Z'],
];
} else {
const firstElement = head(elements);
const lastElement = last(elements);
const { startAngle } = getAngle(firstElement.getModel(), coordinate);
const { endAngle } = getAngle(lastElement.getModel(), coordinate);
const center = coordinate.getCenter();
const radius = coordinate.getRadius();
const innterRadius = coordinate.innerRadius * radius;
path = getSectorPath(center.x, center.y, radius, startAngle, endAngle, innterRadius);
}
if (this.regionPath) {
this.regionPath.attr('path', path);
this.regionPath.show();
} else {
this.regionPath = backgroundGroup.addShape({
type: 'path',
name: 'active-region',
capture: false,
attrs: {
path,
fill: '#CCD6EC',
opacity: 0.3,
},
});
}
}
}
}
/**
* 隐藏
*/
public hide() {
if (this.regionPath) {
this.regionPath.hide();
}
// this.regionPath = null;
this.items = null;
}
/**
* 销毁
*/
public destroy() {
this.hide();
if (this.regionPath) {
this.regionPath.remove(true);
}
super.destroy();
}
}
export default ActiveRegion;