@antv/g2plot
Version:
An interactive and responsive charting library
179 lines (159 loc) • 5.27 kB
text/typescript
import { each, get, map, isArray } from '@antv/util';
import { registerAction, registerInteraction, View, Element, Action } from '@antv/g2';
import { getAllElements, getViews, getSiblingViews } from '../../../utils';
import { clearHighlight, getElementValue } from './utils';
type EventItem = { element: Element; view: View; active: boolean; inactive: boolean };
type ActionParams = { linkField?: string; dim?: 'x' | 'y' };
/**
* 存在多个 view 时,view 之间的联动交互
*
* 提供四个反馈 action,均接受参数:linkField 关联字段,dim 维度
* 1. showTooltip
* 2. active
* 3. highlight
* 4. selected
*
* 附加,两个结束反馈 action:
* 1. hidetooltip
* 2. reset 清除激活和高亮状态
*/
class Association extends Action {
/**
* 获取关联的 elements
*
* - 如果 dim 参数存在,根据 dim 获取相应的 field。与 linkField 不匹配则 return
* - 否则 dim 参数不存在,且 linkField 存在,则作为关联字段
* - 否则若 linkField 不存在,则获取第一个分类字段
* @returns EventItem[]
*/
private getAssociationItems(views: View[], params?: ActionParams): EventItem[] {
const { event } = this.context;
const { linkField, dim } = params || {};
const items = [];
if (event.data?.data) {
const { data } = event.data;
each(views, (v: View) => {
let field = linkField;
if (dim === 'x') {
field = v.getXScale().field;
} else if (dim === 'y') {
field = v.getYScales().find((s) => s.field === field)?.field;
} else if (!field) {
field = v.getGroupScales()[0]?.field;
}
if (!field) {
return;
}
const elements = map(getAllElements(v), (ele) => {
let active = false;
let inactive = false;
const dataValue = isArray(data) ? get(data[0], field) : get(data, field);
if (getElementValue(ele, field) === dataValue) {
active = true;
} else {
inactive = true;
}
return { element: ele, view: v, active, inactive };
});
items.push(...elements);
});
}
return items;
}
/**
* 所有同一层级的 tooltip 显示
*/
public showTooltip(params?: ActionParams) {
const siblings = getSiblingViews(this.context.view);
const elements = this.getAssociationItems(siblings, params);
each(elements, (ele) => {
if (ele.active) {
const box = ele.element.shape.getCanvasBBox();
ele.view.showTooltip({ x: box.minX + box.width / 2, y: box.minY + box.height / 2 });
}
});
}
/**
* 隐藏同一层级的 tooltip
*/
public hideTooltip() {
const siblings = getSiblingViews(this.context.view);
each(siblings, (sibling) => {
sibling.hideTooltip();
});
}
/**
* 设置 active 状态
*/
public active(params?: ActionParams) {
const views = getViews(this.context.view);
const items = this.getAssociationItems(views, params);
each(items, (item: EventItem) => {
const { active, element } = item;
if (active) {
element.setState('active', true);
}
});
}
/**
* 设置 selected 状态
*/
public selected(params?: ActionParams) {
const views = getViews(this.context.view);
const items = this.getAssociationItems(views, params);
each(items, (item: EventItem) => {
const { active, element } = item;
if (active) {
element.setState('selected', true);
}
});
}
/**
* 进行高亮 => 设置 inactive 状态
*/
public highlight(params?: ActionParams) {
const views = getViews(this.context.view);
const items = this.getAssociationItems(views, params);
each(items, (item: EventItem) => {
const { inactive, element } = item;
if (inactive) {
element.setState('inactive', true);
}
});
}
public reset() {
const views = getViews(this.context.view);
each(views, (v) => {
clearHighlight(v);
});
}
}
registerAction('association', Association);
/**
* 相邻 view 的 active 联动(相同维值的 tooltip 联动)
*/
registerInteraction('association-active', {
start: [{ trigger: 'element:mouseenter', action: 'association:active' }],
end: [{ trigger: 'element:mouseleave', action: 'association:reset' }],
});
/**
* 相邻 view 的 active 联动(相同维值的 tooltip 联动)
*/
registerInteraction('association-selected', {
start: [{ trigger: 'element:mouseenter', action: 'association:selected' }],
end: [{ trigger: 'element:mouseleave', action: 'association:reset' }],
});
/**
* 相邻 view 的 highlight 联动, 突出当前 element
*/
registerInteraction('association-highlight', {
start: [{ trigger: 'element:mouseenter', action: 'association:highlight' }],
end: [{ trigger: 'element:mouseleave', action: 'association:reset' }],
});
/**
* 相邻 view 的 tooltip 联动,根据 groupField 进行关联(相同维值的 tooltip 联动)
*/
registerInteraction('association-tooltip', {
start: [{ trigger: 'element:mousemove', action: 'association:showTooltip' }],
end: [{ trigger: 'element:mouseleave', action: 'association:hideTooltip' }],
});