-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
link-by-color.ts
161 lines (155 loc) · 4.38 KB
/
link-by-color.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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;