UNPKG

@antv/g2

Version:

the Grammar of Graphics in Javascript

162 lines (155 loc) 4.49 kB
import Action from '../base'; import { getCurrentElement, getElementValue, getElementsByField } from '../util'; import Element from '../../../geometry/element/'; import { deepMix, each, isFunction } from '@antv/util'; import { LooseObject } from '../../../interface'; import { IGroup, ShapeAttrs } from '../../../dependents'; type LinkActiveStyle = ShapeAttrs | ((style: ShapeAttrs, Element: Element) => ShapeAttrs); /** * Link Elements by color * * public 方法是对外可用的反馈交互。使用方式,如:element-link-by-color:link, element-link-by-color:unlink, element-link-by-color:clear */ class LinkByColor extends Action { private linkGroup: IGroup; private cache: LooseObject = {}; // 获取颜色对应的 scale private getColorScale(view, element) { const colorAttr = element.geometry.getAttribute('color'); if (!colorAttr) { return null; } const scale = view.getScaleByField(colorAttr.getFields()[0]); return scale; } // 获取连接的 path private getLinkPath(element: Element, nextElement: Element) { const view = this.context.view; const { isTransposed } = view.getCoordinate(); const bbox = element.shape.getCanvasBBox(); const nextBBox = nextElement.shape.getCanvasBBox(); const path = isTransposed ? [ ['M', bbox.minX, bbox.minY], ['L', nextBBox.minX, nextBBox.maxY], ['L', nextBBox.maxX, nextBBox.maxY], ['L', bbox.maxX, bbox.minY], ['Z'], ] : [ ['M', bbox.maxX, bbox.minY], ['L', nextBBox.minX, nextBBox.minY], ['L', nextBBox.minX, nextBBox.maxY], ['L', bbox.maxX, bbox.maxY], ['Z'], ]; return path; } // 添加连接的图形 private addLinkShape(group: IGroup, element: Element, nextElement: Element, activeStyle?: LinkActiveStyle) { const style = { opacity: 0.4, fill: element.shape.attr('fill'), }; group.addShape({ type: 'path', attrs: { ...deepMix({}, style, isFunction(activeStyle) ? activeStyle(style, element) : activeStyle), path: this.getLinkPath(element, nextElement), }, }); } // 使用图形连接 private linkByElement(element: Element, activeStyle?: LinkActiveStyle) { const view = this.context.view; const scale = this.getColorScale(view, element); if (!scale) { return; } const value = getElementValue(element, scale.field); if (!this.cache[value]) { const elements = getElementsByField(view, scale.field, value); const linkGroup = this.linkGroup; const group = linkGroup.addGroup(); this.cache[value] = group; // 缓存 const count = elements.length; each(elements, (el, index) => { if (index < count - 1) { const nextEl = elements[index + 1]; this.addLinkShape(group, el, nextEl, activeStyle); } }); } } // 移除连接 private removeLink(element) { const scale = this.getColorScale(this.context.view, element); if (!scale) { return; } const value = getElementValue(element, scale.field); if (this.cache[value]) { this.cache[value].remove(); this.cache[value] = null; } } /** * 连接 elements * * @usage * registerInteraction('xxx', { * start: [ * { * trigger: 'interval:mouseenter', * action: 'element-link-by-color:link', * arg: { * // style: { fill: 'red' } * style: (style, element) => ({ fill: 'red' }) * }, * }, * ], * }); */ public link(args?: { style: LinkActiveStyle }) { const context = this.context; if (!this.linkGroup) { // 不允许被拾取 this.linkGroup = context.view.foregroundGroup.addGroup({ id: 'link-by-color-group', capture: false, }); } const element = getCurrentElement(context); if (element) { this.linkByElement(element, args?.style); } } /** * 取消连接 elements */ public unlink() { const element = getCurrentElement(this.context); if (element) { this.removeLink(element); } } /** * 清除所有连接 */ public clear() { if (this.linkGroup) { this.linkGroup.clear(); } this.cache = {}; } /** * 销毁 */ destroy() { super.destroy(); if (this.linkGroup) { this.linkGroup.remove(); } } } export default LinkByColor;